jueves, 12 de junio de 2014

Expresiones Lambda en C# - Parte 5: Ejemplos de Expresiones Lambda

Tabla de Contenido

0. Introducción
1. Ejemplo No. 1: Delegado Genérico con Expresión Lambda
2. Ejemplo No. 2: Expresión Lambda con Variables Capturadas
3. Ejemplo No. 3: Listas Genéricas con Expresiones Lambda
4. Ejemplo No. 4: Expresión Lambda como Parámetro de Método (Encapsulación)
5. Ejemplo No. 5: Formulario con Control Asincrónico
6. Conclusiones
7. Glosario
8. Literatura & Enlaces

0. Introducción

Finalmente, en esta última parte de la serie de artículos de expresiones lambda presentaré varios ejemplos para afianzar varios de los conceptos teóricos y prácticos aprendidos en esta serie (compuesta por 5 partes). Los ejemplos van desde definiciones simples de expresiones lambda, uso de variables capturadas, especificación de una expresión sobre el método de extensión Where de List<T>, hasta uso el uso de formas sintácticas más complejas en formularios con controles asincrónicos.

1. Ejemplo No 1: Delegado genérico con Expresión Lambda

En este primer ejemplo haremos uso de uno de los delegados genéricos integrados en .NET Framework, le asignaremos una expresión lambda para acortar el camino, es decir, nos evitaremos escribir código en un método formal (con nombre).

Archivo de código fuente DelegadoExpresionLambda.cs [enlace alternativo]:
En la línea 10 declaramos un delegado genérico utilizando la versión Func<T1, T2, TResult> [2], que como vemos se trata de un delegado con la firma que admite tres parámetros de tipo genéricos: los dos primeros corresponden con dos parámetros de entrada, y el tercero de tipo de retorno.

> Prueba de ejecución.

2. Ejemplo No. 2: Expresión Lambda con Cariables Capturadas

Este segundo ejemplo consiste en demostrar cómo una variable capturada en un método que retorna una instancia de un delegado genérico se mantiene en foco a pesar de que el método ya no se encuentre en el stack:

Archivo de código fuente VariableCapturadaExpresionLambda.cs [enlace alternativo]:

Sobre las líneas 7-14 se declara el método IncrementarContadorLocal que retorna un delegado de naturaleza Func<TResulta> que en su cuerpo declarativo incluye la declaración de una variable local y el retorno de una expresión lambda que captura la variable exterior contador del siguiente modo:

() => contador++


Esta expresión lambda es encapsulada en el tipo de delegado genérico mencionado anteriormente. Ya desde código cliente (líneas 16-31) creamos una variable de Func<TResulta>, luego encapsulamos en ese delegado el método IncrementarContadorLocal, esto va a producir que la variable contador (línea 9) quede capturada por la expresión lambda, y que pesar de que el método en donde es declarada ya esté por fuera del stack, se pueda usar su valor con la invocación indirecta de la expresión lambda (líneas 28-30).


> Prueba de ejecución.

3. Ejemplo No. 3: Listas genéricas con Expresiones Lambda

Utilizaremos el método de extensión Where definido en la clase genérica List<T> para crear un listado filtrado de los elementos de las listas originales.

Archivo de código fuente ListGenericaExpresionLambda.cs [enlace alternativo]:

En la línea 10 crea una instancia de List<T> con varios nombres de países. Más adelante, en la línea 16 usamos la expresión lambda:

pais => pais.Length <= 6


que se traduce en: conjunto de nombres de países en donde el número de caracteres de cada nombre de país es menor o igual a 6. Esta expresión lambda nos sirve de filtro el cual podemos establecer en el método Where, y qué este se encargue de generar una instancia IEnumerable<T> [6] con la colección de nombres de países (cadenas de caracteres) con el filtro descrito.



De manera análoga, creamos una lista con los números de 0-9 y usamos las expresiones lambda:


numero => numero % 2 != 0

-y-

numero => numero % 2 == 0


para generar un listado filtrado de números impares y otro con números pares, respectivamente.


> Prueba de ejecución.

4. Ejemplo No. 4: Expresión Lambda como Parámetro de Método (Encapsulación)

Declararemos un método con la siguiente firma:
  • Parámetros:
    • Delegado genérico Func<T1, T2, TResult>
    • Dos parámetros tipo int.
  • Tipo de retorno int.
Desde código cliente invocaremos este método pasando una expresión lambda y dos números enteros.

Archivo de código fuente ExpresionLambdaComoParametro.cs [enlace alternativo]:
Declaramos el método Calcular en las líneas 9-12. Este método posee la firma descrita anteriormente. Cabe destacar que el parámetro Func<int, int, int> operacion encapsula una expresión lambda que posea dos parámetros y un tipo de retorno int.


En el código cliente (líneas 14-25) solicitamos al usuario la introducción de dos números enteros; enseguida (líneas 21-25) realizamos varios cálculos de la siguiente manera:


Por ejemplo, para la suma pasamos la expresión lambda

(x,y) => x + y


la cual corresponde con una operación binaria (alusivo al nombre del parámetro del delegado en el método Calcular). De forma análogo para las demás operaciones binarias (i.e., resta, producto, y cociente).


> Prueba de ejecución.


[Nota: En ideone la especificación de argumentos o valores de entrada por el usuario se especifican en la pestaña Input (ver Figura 1).]
Entrada de datos en ideone.com
Figura 1. Entrada de datos en ideone.com.

5. Ejemplo No. 5: Formulario con Control Asincrónicos

Este ejemplo se presentó al final de la sección no. 2 de Expresiones Lambda y Asincronismo. Lo vuelvo a tomar como instancia ejemplar con el único propósito de demostrar las capacidades asincrónicas que podemos atribuir a los controles integrales de un interfaz de usuario por medio de expresiones lambda, el modificador async [7], y el operador await [8].

Archivo de código fuente FormularioConAsync.cs [enlace alternativo]:
Observemos como en la línea 75 asignamos al evento Click una expresión lambda precedida por el modificador async:

async (sender, e) =>
{
Task<long> tarea = CalculoFibonacci (long.Parse(txtNumero.Text));

long fibonacci = await tarea;

lblResultado.Text = String.Format("Resultado: {0}", fibonacci.ToString());
}

Sobre el método asincrónico CalculoFibonacci (líneas 101-114) incluimos la lógica para realizar el cálculo de la serie Fibonacci; sin embargo, en la línea 111 se establece un retardo arbitrario con el método Task.Delay [7] para simular un tiempo de procesamiento.

La interfaz está compuesta por otro botón que nos muestra un mensaje cuando es pulsado. Al evento `Click` de este botón le hemos asignado una expresión lambda:

(sender, e) => 
MessageBox.Show("La interfaz no se congela mientras se calcula la serie Fibonacci.");

que lo único que nos muestra en pantalla es un mensaje en un cuadro de esto, nada nuevo, por supuesto; pero con el hecho que podamos activar el evento de este botón demostramos la capacidad asincrónica que nos entrega el uso del modificador async y el operador await sobre los métodos asincrónicos.

Compilación:

  1. csc /target:exe FormularioConAsync.cs

Ejecución:

  1. .\FormularioConAsync.exe

Resultado:

6. Conclusiones

La serie de Expresiones Lambda nos ha formado una idea amplia del uso de este tipo de expresiones que son importante utilidad (simplificación de código, legibilidad de la especificación de un método anónimo como instancia de un delegado, asincronismo en formularios, entre otros más). En particular, esta entrega se centró en demostrar varios ejemplos que resumen varios de los conceptos teóricos y prácticos aprendidos a lo largo de la serie.

7. Glosario

  • Asincronismo
  • Expresión lambda
  • Lista genérica
  • Modificador async
  • Operador await

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]: Func(T1, T2, TResult) Delegate (System) - http://msdn.microsoft.com/en-us/library/bb534647(v=vs.110).aspx
[3]: Func(TResult) Delegate (System) - http://msdn.microsoft.com/en-us/library/bb534960(v=vs.110).aspx
[4]: List(T) Class (System.Collections.Generic) - http://msdn.microsoft.com/en-us/library/6sh2ey19(v=vs.110).aspx
[5]: Enumerable.Where(TSource) Method (IEnumerable(TSource), Func(TSource, Boolean)) (System.Linq) - http://msdn.microsoft.com/en-us/library/bb534803(v=vs.110).aspx
[6]: IEnumerable(T) Interface (System.Collections.Generic) - http://msdn.microsoft.com/en-us/library/9eekhta0(v=vs.110).aspx
[7]: async (C# Reference) - http://msdn.microsoft.com/en-us/library/hh156513.aspx
[8]: await (C# Reference) - http://msdn.microsoft.com/en-us/library/vstudio/hh156528(v=vs.110).aspx


J

No hay comentarios:

Publicar un comentario

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