viernes, 23 de mayo de 2014

Tipos Genéricos en C# - Parte 8: Delegados Genéricos

Tabla de Contenido

0. Introducción
1. ¿Qué es un Delegado?
2. Delegados Genéricos
3. Otras Características
3.1 Conversión de métodos de grupos
3.2 Uso de parámetros de tipo de nivel de clase
3.3 Restricciones de parámetros de tipo
4. Conclusiones
5. Glosario
6. Literatura & Enlaces

0. Introducción

Llega la oportunidad de hablar de delegados genéricos en C#. Vamos a cubrir el concepto general de delegado, enseguida la diferencia (a través de conceptos, beneficios, y ejemplos entre un delegado genérico y uno no-genérico). En breve, también hablaremos sobre los delegados estándar introducidos en el Framework .NET. En todo el transcurso será necesario que hablemos de una característica (regla de inferencia, en abstracto) para los delegados: conversión de grupo de métodos.

1. ¿Qué es un Delegado?

Un delegado es un tipo que referencia a métodos que cumplen con una firma (signatura) y un tipo de retorno. Ejemplo de declaración de un delegado en C#:

{modificador acceso} delegate {tipo retorno} {identificador delegado}({parámetros});

Descripción puntual:
  • {modificador acceso}: Especificación del modificador de acceso (i.e., public, internal, private, protected, protected internal -cfr. Modificadores de Acceso en C#-.)
  • delegate: Palabra clave para declaración de un delegado en C# [5].
  • {tipo retorno}: Cualquier tipo (clase, interfaz, enumeración, etc.) devuelto por el delegado.
  • {identificador delegado}: Un identificador para el delegado que siga las reglas de nomenclatura de identificadores.
  • {parámetros}: Conjunto de parámetros (cualquier tipo).
Ejemplo particular de un delegado:

public delegate int Calcular(int a, int b);

Uso:

Asumamos que tenemos cuatro funciones matemáticas que operan sobre enteros:

public int Sumar(int a, int b) { }

public int Restar(int a, int b) { }

public int Multiplicar(int a, int b) { }

public int Dividir(int a, int b) { }

Podemos usar nuestro delegado de la siguiente manera:

Calcular suma = Sumar;

int a = 3;
int b = 5;

Console.WriteLine("Suma: {0}", suma(a, b).ToString());

Calcular resta = Restar;

Console.WriteLine("Suma: {0}", resta(a, b).ToString());

(Omito el uso de las operaciones Multiplicar, y Dividir, porque siguen la misma lógica que las dos anteriores.)

¿Y qué ocurre si introducimos métodos (aritméticos) que operen con tipos por valor long, short, decimal, &c.?

Respuesta: pasemos a la siguiente sección.

2. Delegados Genéricos

Un delegado genérico es un un delegado que permite la especificación en un su declaración parámetros de tipo. Esta es la sintaxis declarativa:

{modificador acceso} delegate {tipo retorno} {identificador delegado}<T [,T,...]>({parámetros});

Descripción puntual:
  • {modificador acceso}: Especificación del modificador de acceso (i.e., publicinternalprivateprotectedprotected internal -cfr. Modificadores de Acceso en C#-.)
  • delegate: Palabra clave para declaración de un delegado en C# [5].
  • {tipo retorno}: Cualquier tipo (clase, interfaz, enumeración, etc.) devuelto por el delegado.
  • {identificador delegado}: Un identificador para el delegado que siga las reglas de nomenclatura de identificadores.
  • <T [,T,...]>: Conjunto de parámetros de tipo (cfr. Parámetros de Tipo)
  • {parámetros}: Conjunto de parámetros (cualquier tipo).
Ejemplo particular de un delegado genérico:

public delegate T Calcular<T>(T a, T b);

Este delegado genérico acepta dos argumentos de cualquier tipo, de igual modo, el tipo de retorno es genérico.

Asumamos que tenemos un método genérico para la suma, entonces:

public T Sumar<T>(T a, T b)
{
dynamic num1 = a;
dynamic num2 = b;

return num1 + num2;
}

Nuestro nuevo delegado genérico nos permite operar de la siguiente manera:

Calcular<double> sumaDoubles = new Calcular<double>(Sumar<double>);

Calcular<int> sumaInts = new Calcular<int>(Sumar<int>);

Console.WriteLine(sumaDoubles(7.3, 9.3).ToString());

Console.WriteLine(sumaDoubles(7, 9).ToString());

Ejemplo completo:


Es evidente que con el delegado genérico nos ahorramos la definición de delegados no genéricos para cada tipo de dato a operar: sinónimo de reusabilidad.

3. Otras Características

3.1 Conversión de métodos de grupos

La conversión de métodos de grupo es una característica disponible desde la versión 2.0 del C#, y simplifica la instanciación de delegados genéricos.

Asumamos ese delegado:

public delegate void Delegado<T>(T elemento);

y este método no-genérico:

public void Notificar(int i) { }

ahora instanciamos un delegado y referenciamos al método Notificar:

Delegado<int> del = new Delegado<int>(Notificar);

El equivalente con el uso de la conversión de métodos de grupo, la anterior sentencia queda simplificada a:

Delegado<int> del = Notificar;

3.2 Uso de parámetros de tipo de nivel de clase

Un delegado puede acceder a los parámetros de tipo de nivel de clase. Así:

class Pila<T>
{
T[] datos;
int indice;

public delegate void DelegadoNotificiones(T[] datos);
}

3.3 Restricciones de Parámetros de Tipo

Las restricciones de parámetros de tipo de delegados no están disponibles en la versión 4.0.30319.18408 del compilador de C#.

4. Conclusiones

Entendimos que los delegados genéricos contribuyen a la reusabilidad de código: el ejemplo en la sección 2 así lo demostró. También aprendimos a usar el concepto de simplificación de creación de instancias de delegados a través de la conversión de métodos de grupos. Casi al final vimos que los parámetros de tipo de nivel de clase pueden ser usados por lo delegados genéricos. Finalmente, comprendimos que las restricciones de parámetros de tipo no están disponibles en C# (versión del compilador 4.0.30319.18408).

5. Glosario

  • Delegado
  • Delegado genérico
  • Parámetro de tipo
  • Reusabilidad
  • Tipo

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 Delegates (C# Programming Guide) - http://msdn.microsoft.com/en-us/library/sx2bwtw7.aspx
[3]: Delegates (C# Programming Guide) - http://msdn.microsoft.com/en-us/library/ms173171.aspx
[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]: delegate (C# Reference) - http://msdn.microsoft.com/en-us/library/900fyy8e.aspx
[6]: 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
[7]: Taxonomía de Tipos de Dato por Valor - http://ortizol.blogspot.com/2013/07/taxonomia-de-los-tipos-predefinidos-de-c.html
[8]: Delegates 101 - Part III: Generic Delegates - CodeProject - http://www.codeproject.com/Articles/192027/Delegates-Part-III-Generic-Delegates
[9]: Generic Delegates in C# - http://www.c-sharpcorner.com/UploadFile/mahesh/generic-delegates-in-C-Sharp/
[10]: Understanding Generics—Creating Generic Delegates — Visual C# Developer Center - http://tutorials.csharp-online.net/Understanding_Generics%E2%80%94Creating_Generic_Delegates
[11]: C# Tutorial - The Built-In Generic Delegate Declarations - Tech.pro - http://tech.pro/tutorial/861/csharp-tutorial-the-built-in-generic-delegate-declarations


J

No hay comentarios:

Publicar un comentario

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