jueves, 22 de mayo de 2014

Tipos Genéricos en C# - Parte 6: Métodos Genéricos

Tabla de Contenido

0. Introducción
1. Definición de Método Genérico
1.1 Declaración de un Método Genérico
1.2 Ejemplo de un método genérico
2. Reglas de Inferencia
3. Acceso Parámetros de Tipo de Nivel de Clase
4. Restricciones sobre Parámetros de Tipo
5. Sobrecarga
6. Conclusiones
7. Glosario
8. Literatura & Enlaces

0. Introducción

Antes de que avancemos a la séptima parte en donde hablaremos acerca de delegados genéricos, detengamos en otro de los temas importantes relacionados con tipos genéricos: métodos genéricos. Definiremos qué es un método genérico, describiremos la sintaxis declarativa, sin excepción incluiremos ejemplos básicos. Además, nos detendremos en la inferencia de parámetros, métodos genéricos sobrecargados, y algunas advertencia sobre el uso de parámetros de tipo de clase genérica.

1. Definición de un Método Genérico

Sencillamente, un método genérico es aquel que tiene especificado en su firma un conjunto de parámetros de tipo. Gracias a esta propiedad de genericidad, el método puede operar sobre cualquier tipo pasado como argumento y realizar operaciones generales para los tipos para los que fue concebido (propiedad de generalización). (Inclusive, disfrutará de los beneficios fundamentales de los tipos genéricos: alto desempeño, seguridad de tipos, y reusabilidad -cfr. Beneficios de los Tipos Genéricos-)

1.1 Declaración de un método genérico

Esta es la sintaxis general de declaración de un método genérico en C#:

{modificador de acceso} {tipo retorno} {nombre método}<T [,T,...]>({parámetros}) {restricciones}
{
// Implementación
}

Descripción puntual:
  • {modificador de acceso}: Especificación de uno de los modificadores de acceso disponibles (-Modificadores de Acceso en C#-.)
  • {tipo retorno}: Cualquiera de los tipos de datos de la biblioteca de clases del Framework .NET, los propios creados por el programadores, o un parámetro de tipo.
  • {nombre método}: Identificadores (nombre) del método (debe seguir las reglas sintácticas de declaración de identificadores.)
  • <T [,T,...]>: Conjunto de parámetros de tipo.
  • {parámetros}: Parámetros (tipos de la biblioteca de clases, parámetros de tipo).
  • {restricciones}: Conjunto de restricciones para los parámetros de tipos (cfr. Parámetros de Tipo.)
Un ejemplo particular básico:

public T MetodoGenerico<T>(T elemento, int entero)
{
// Implementación
}

Con varios parámetros de tipo:

public void MetodoGenerico<T, U>(T arg1, U arg2)
{
// Implementación
}

1.2 Ejemplo de un método genérico

A continuación un método genérico estático para alternar el valor de dos argumentos:

public static void Alternar<T>(ref T valor1, ref T valor2)
{
T temp = valor1;
valor1 = valor2;
valor2 = temp;
}

Este método recibe dos parámetros por referencia (modificador ref -cfr. Variables y Parámetros en C# - Parte 2-). Este podría ser el código cliente para invocar al método Alternar:

public static void Main()
{
  int a = 2;
int b = 3;

Alternar<int>(ref a, ref b);

Console.WriteLine("Valor de `a`: {0} - Valor de `b`: {1}", a.ToString(), b.ToString());
}

Cuando invocamos al método genérico Alternar, hemos especificado el tipo por valor concreto int, sin embargo el compilador es capaz de inferir el parámetro de tipo con base en los argumentos referenciados (i.e., a, y b), y podemos invocar al método Alternar de la siguiente manera:

Alternar(ref a, ref b);

> Prueba de ejecución.

Resultado:

Antes de invocar a `Alternar`:
 Valor de `a`: 2 - Valor de `b`: 3

Después de invocar a `Alternar`:
 Valor de `a`: 3 - Valor de `b`: 2

2. Reglas de Inferencia

Ya en la sección 1.2 exploramos una de las reglas de inferencia a través del método Alternar, dado que lo podemos invocar de una de estas dos formas:

Alternar<int>(ref a, ref b);

-o-

Alternar(ref a, ref b);

Y el compilador hará su trabajo en tiempo de compilación. (Vale sumar que esta regla de inferencia aplica tanto para métodos estáticos como métodos de instancia [2]).

Puntos a considerar:
  • La inferencia no funciona para los métodos genéricos que no posean argumentos.
  • Todo el proceso de inferencia de tipos se lleva a cabo en tiempo de compilación.
  • Se incluirán como métodos sobrecargados candidatos, aquellos que hayan pasado la prueba de inferencia de tipos.

3. Acceso a Parámetros de Tipo de Clase Genérica

Los métodos no-genéricos (estáticos o miembros), pueden acceder a los parámetros de tipo de nivel de clase. Así:

class ClaseGenerica<T>
{
void MetodoNoGenerico(T arg1, T arg2)
{
// Implementación
}
}

Por otro lado, en tiempo de compilación, los métodos genéricos que reusen los parámetros de tipo de nivel de clase genérica, el compilador generará la advertencia CS0693 [8]:
...within the method scope, the argument supplied for the inner T hides the argument supplied for the outer T.
Para sortear este inconveniente, lo recomendado es usar un identificador distinto para el parámetro de tipo.

Ejemplos de ~mal o buen uso:

class ListaGenerica<T>
{
// Genera advertencia CS0663
void MetodoGenerico<T> () { }
}

-y-

class ListaGenerica<T>
{
void MetodoGenerico<U> () { }
}

4. Restricciones sobre Parámetros de Tipo

Podemos que los métodos genéricos se especialicen estableciendo restricciones sobre los parámetros de tipo. Para poner como caso, el método genérico Alternar puede mutarse de la siguiente manera:

void Alternar<T>(ref T valor1, ref T valor2) where T : System.IComparable<T>
{
  T temp;

if (valor1.CompareTo(valor2) > 0)
{
temp = valor1;
valor1 = valor2;
valor2 = temp;
}
}

5. Sobrecarga

En la sección 2 ya mencionamos que la operación de sobrecarga también está disponible para métodos genéricos. Se siguen las mismas reglas de declaración y evaluación.

Ejemplos básicos:

void Tarea() { }

void Tarea<T>() { }

void Tarea<T, U>() { }

6. Conclusiones

Los métodos genéricos son otra pieza fundamental en la creación de tipos genéricos (clases e interfaces). Sencillamente un método genérico es un método que contiene parámetros (o argumentos) de tipo. También se atribuye los beneficios de alto desempeño, reusabilidad, y seguridad de tipos. Conocimos acerca de reglas de inferencia, parámetros de tipo, restricciones, y sobrecarga sobre los métodos genéricos.

7. Glosario

  • Alto desempeño
  • Argumento de tipo
  • Clase
  • Estático
  • Interfaz
  • Método estático
  • Método genérico
  • Parámetro de tipo
  • Restricción
  • Reusabilidad
  • Seguridad de tipos
  • Sobrecarga

8. Literatura & Enlaces

[1]: C# 5.0 in a Nutshell by Joseph Albahari and Ben Albahari. Copyright 2012 Joseph Albahari and Ben Albahari, 978-1-449-32010-2.
[2]: Generic Methods (C# Programming Guide) - http://msdn.microsoft.com/en-us/library/twcad0zb.aspx
[3]: Tipos Genéricos en C# - Parte 2: Beneficios | OrtizOL - Experiencias Construcción Software (xCSw) - http://ortizol.blogspot.com/2014/05/interfaces-en-c-parte-2.html
[4]: Modificadores de Acceso en C# | OrtizOL - Experiencias Construcción Software (xCSw) - http://ortizol.blogspot.com/2014/04/modificadores-de-acceso-en-c.html
[5]: Tipos Genéricos en C# - Parte 3: Parámetros de Tipo - http://ortizol.blogspot.com/2014/05/tipos-genericos-en-c-parte-3-parametros.html
[6]: Variables y Parámetros en C# - Parte 1 | OrtizOL - Experiencias Construcción Software (xCSw) - http://ortizol.blogspot.com/2013/09/variables-y-parametros-en-c-parte-2.html
[7]: Sobrecarga y Resolución Llamada Métodos en C# | OrtizOL Experiencias Construcción Software - http://ortizol.blogspot.com/2014/02/sobrecarga-y-resolucion-llamada-metodos.html
[8]: Compiler Warning (level 3) CS0693 - http://msdn.microsoft.com/en-us/library/0ah54ze5(v=vs.90).aspx
[9]: C# Generic Method - http://www.dotnetperls.com/generic-method
[10]: C# Generics - http://www.tutorialspoint.com/csharp/csharp_generics.htm
[11]: C# Tutorials: A Generic Method With Various Parameters - http://www.ww.functionx.com/csharp1/topics/generics2.htm


J

No hay comentarios:

Publicar un comentario

Envíe sus comentarios, dudas, sugerencias, críticas. Gracias.