Tabla de Contenido
0. Introducción1. Delegados Genéricos: Action
1.1 Delegado Action
1.2 Delegado Action<T>
2. Delegados Genéricos: Func
2.1 Delgado Func<TResult>
3. Conclusiones
4. Glosario
5. Literatura & Enlaces
0. Introducción
En este último artículo de la serie de delegados en C#, pasaremos a explorar los delegados predefinidos en Microsoft .NET Framework: Func y Action. Veremos la utilidad de estos delegados incorporados para promover la reutilización propuesta en la biblioteca de clases del Framework. Introduciré varios ejemplos de contraste entre definir nuestros propios delegados y usar los predefinidos.
1. Delegados Genéricos: Action
Ya hemos tenido la oportunidad de hablar acerca de los tipos genéricos en C#, más precisamente acerca de los delegados genéricos (Tipos Genéricos en C# - Parte 8: Delegados Genéricos), lo que tenemos que hacer ahora es comprender los delegados que incorpora Microsoft .NET Framework y que nos pueda hacer la tarea de confección de código mucho más amena.
Continuando, empecemos por explorar algunos de estos delegados genéricos:
1.1 Delegado Action
Empecemos por conocer su firma [3]:
public delegate void Action()
Su especificación consiste de cero parámetros, y su tipo de retorno void. Entonces, ahora pasemos a explorar a través de ejemplos su utilidad. En primera instancia cabe decir que el uso de este delegado nos va a ahorrar la escritura de un delegado personalizado, como:
public delegate void Delegado();
Nota desde [3]:
Respecto a lo anterior, la version Action() posee su contraparte con tipo de retorno genérico: Func<TResult> [7].
Archivo de código fuente SinAction.cs [enlace alternativo]:
En la línea 7 se define explícitamente el delegado MostrarValor, más específicamente:
public delegate void MostrarValor();
Y lo usamos en la invocación indirecta en la línea 35.
[Nota: Lo anterior puede resultar muy sencillo para quienes ya hayan leído las 4 entregas anteriores de esta serie de artículos de «Delegados en C#».]
Ahora si utilizamos el delegado genérico predefinido Action:
Archivo de código fuente ConAction.cs [enlace alternativo]:
A destacar la línea 34, en donde usamos el delegado Action para declarar una instancia de este tipo de delegado y asignarle la referencia al método MostarEnVentana.
Si comparamos este código con el del archivo de código fuente SinAction.cs, nos hemos deshecho de la declaración del delegado MostrarValor, dado que la firma del delegado incorporado Action es la misma, y lo podemos reutilizar. Esto brinda un grado de abstracción extra en la tarea de codificación.
Action del = delegate()
{
nombre.MostrarEnVentana();
}
O sino, con una expresión lambda:
Action del = () => nombre.MostrarEnVentana();
Descripción puntual:
public delegate void Delegado();
Nota desde [3]:
Figura 1. Alternativa a Action() con tipo de retorno. |
Respecto a lo anterior, la version Action() posee su contraparte con tipo de retorno genérico: Func<TResult> [7].
Archivo de código fuente SinAction.cs [enlace alternativo]:
En la línea 7 se define explícitamente el delegado MostrarValor, más específicamente:
public delegate void MostrarValor();
Y lo usamos en la invocación indirecta en la línea 35.
[Nota: Lo anterior puede resultar muy sencillo para quienes ya hayan leído las 4 entregas anteriores de esta serie de artículos de «Delegados en C#».]
Ahora si utilizamos el delegado genérico predefinido Action:
Archivo de código fuente ConAction.cs [enlace alternativo]:
A destacar la línea 34, en donde usamos el delegado Action para declarar una instancia de este tipo de delegado y asignarle la referencia al método MostarEnVentana.
Si comparamos este código con el del archivo de código fuente SinAction.cs, nos hemos deshecho de la declaración del delegado MostrarValor, dado que la firma del delegado incorporado Action es la misma, y lo podemos reutilizar. Esto brinda un grado de abstracción extra en la tarea de codificación.
1.1.1 Action con método anónimos
La línea 34 la pudimos haber reemplazo de la siguiente manera (usando un método anónimo -cfr. Delegados en C# - Parte 2: Métodos Anónimos-):Action del = delegate()
{
nombre.MostrarEnVentana();
}
O sino, con una expresión lambda:
Action del = () => nombre.MostrarEnVentana();
1.2 Delegado Action<T>
Tenemos otro delegado genérico que posee la siguiente firma [6]:
public delegate void Action<in T>(T obj)
Su uso es análogo al de la sección 1.1, sin embargo incluyo este ejemplo:
Archivo de código fuente SinActionT.cs [enlace alternativo]:
En línea 6 se declara el delegado MostrarMensaje, con la siguiente especificación:
if (Environment.GetCommandLineArgs().Length > 1)
Ahora, utilicemos la versión de demostración con Action<T>:
Archivo de código fuente ConActionT.cs [enlace alternativo]:
En la línea 10 ocurre la siguiente acción:
Action<string> mm;
es la declaración de un delegado genérico con tipo string. Ocurre la misma evaluación que en el ejemplo anterior (esta vez en la línea 12).
> Prueba de ejecución:
[Nota: Para saber más, recomiendo leer la documentación de MSDN.]
public delegate void Action<in T>(T obj)
Su uso es análogo al de la sección 1.1, sin embargo incluyo este ejemplo:
Archivo de código fuente SinActionT.cs [enlace alternativo]:
En línea 6 se declara el delegado MostrarMensaje, con la siguiente especificación:
- Tipo retorno: void
- Parámetros: string
if (Environment.GetCommandLineArgs().Length > 1)
Ahora, utilicemos la versión de demostración con Action<T>:
Archivo de código fuente ConActionT.cs [enlace alternativo]:
En la línea 10 ocurre la siguiente acción:
Action<string> mm;
es la declaración de un delegado genérico con tipo string. Ocurre la misma evaluación que en el ejemplo anterior (esta vez en la línea 12).
> Prueba de ejecución:
1.3 Otros delegados genéricos
Microsoft .NET Framework cuenta otros 15 delegados genéricos, partiendo con Action() hasta Action(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16) [8].[Nota: Para saber más, recomiendo leer la documentación de MSDN.]
2. Delegados Genéricos: Func
Es la oportunidad de hablar los delegados genéricos incorporados en Microsoft .NET Framework: Func; que a diferencia de los delegados genéricos Action, estos sí retornan un tipo genérico.
2.1 Delegado Func<TResult>
Este es delegado genérico es la alternativa al que exploramos en la sección 1.2, ya que posee tipo de retorno. Conozcamos su firma [9]:
public delegate TResult Func<out TResult>()
public delegate TResult Func<out TResult>()
Descripción puntual:
- Tipo de retorno: Genérico TResult
- out: (recomiendo lectura de Variables y Parámetros en C# - Parte 2)
- Parámetros: «ninguno»
2.1.1 Ejemplo sin Func<TResult>
Creemos un ejemplo sin el uso del delegado genérico Func<T>:
Archivo de código fuente SinFunc.cs [enlace alternativo]:
En la línea 6 creamos el delegado Escribir con la siguiente firma:
public delegate bool Escribir();
Tengamos en cuenta que su tipo de retorno, es bool. En la siguiente sub-sección vamos a aprovechar para usar el delegado genérico integrado al que le podemos especificar ese tipo de retorno.
Observemos que en la línea 12 creamos una instancia de Func con el tipo específico bool. Gracias al grado de genericidad de Func, podemos asignar la referencia al método EnviarAArchivo de la clase SalidaContenido.
Archivo de código fuente SinFunc.cs [enlace alternativo]:
En la línea 6 creamos el delegado Escribir con la siguiente firma:
public delegate bool Escribir();
Tengamos en cuenta que su tipo de retorno, es bool. En la siguiente sub-sección vamos a aprovechar para usar el delegado genérico integrado al que le podemos especificar ese tipo de retorno.
2.2.2 Ejemplo con Func<TResult>
Archivo de código fuente ConFunc.cs [enlace alternativo]:Observemos que en la línea 12 creamos una instancia de Func con el tipo específico bool. Gracias al grado de genericidad de Func, podemos asignar la referencia al método EnviarAArchivo de la clase SalidaContenido.
2.2 Otros delegados genéricos Func
En el namespace System podemos encontrar el resto de delegados genéricos integrados Func:
- Func(T, TResult)
- Func(T1, T2, TResult)
- Func(T1, T2, T3, TResult)
- ...
- Func(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, TResult)
[Nota: Para saber más, recomiendo leer la documentación de MSDN.]
3. Conclusiones
Conocimos los delegados genéricos de Microsoft .NET Framework, con los cuales nos podemos ahorrar la escritura de una cantidad de código. Exploramos los delegados genéricos Action, el cual posee hasta 17 versiones distintas (difieren en el número de parámetros); y los delegados genéricos Func corresponde con delegados con tipo de retorno, y parámetros, opuestos a los primeros (i.e., Action).
4. Glosario
- Action
- Delegado
- Delegado genérico
- Expresión lambda
- Método anónimo
- Tipo genérico
5. 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]: C#/.NET Little Wonders: The Generic Action Delegates - http://geekswithblogs.net/BlackRabbitCoder/archive/2011/11/03/c.net-little-wonders-the-generic-action-delegates.aspx
[3]: Action Delegate (System) - http://msdn.microsoft.com/en-us/library/system.action(v=vs.110).aspx
[4]: Tipos Genéricos en C# - Parte 8: Delegados Genéricos - http://ortizol.blogspot.com/2014/05/tipos-genericos-en-c-parte-8-delegados.html
[5]: Delegados en C# - Parte 2: Métodos Anónimos | OrtizOL - Experiencias Construcción Software (xCSw) - http://ortizol.blogspot.com/2014/05/delegados-en-csharp-parte-2-metodos-anonimos.html
[6]: Action(T) Delegate (System) - http://msdn.microsoft.com/en-us/library/018hxwa8(v=vs.110).aspx
[7]: Func(TResult) Delegate (System) - http://msdn.microsoft.com/en-us/library/bb534960(v=vs.110).aspx
[8]: Action(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16) Delegate (System) - http://msdn.microsoft.com/en-us/library/dd402872(v=vs.110).aspx
[9]: Func(TResult) Delegate (System) - http://msdn.microsoft.com/en-us/library/bb534960(v=vs.110).aspx
[10]: Variables y Parámetros en C# - Parte 2 | OrtizOL - Experiencias Construcción Software (xCSw) - http://ortizol.blogspot.com/2013/09/variables-y-parametros-en-c-parte-2.html
J