martes, 24 de junio de 2014

Expresiones Lambda






Vamos con la evolución de los métodos anónimos, para muchos las muy polémicas y comprometidas Expresiones Lambda.
Aparecieron en la versión 3.0 del Framework y vinieron a ser el apoyo ideal para nuestro bien amado LinQ. Las Expresiones Lambda tienen la capacidad de manejar eventos ‘inline’ asignando bloques de código a delegados o eventos, al igual que lo hacían nuestros métodos anónimos, pero de una forma más reducida y concisa, ‘echando mano’ de la inferencia de tipos.

Intentaremos desmitificarlas haciendo una comparativa con los métodos anónimos y desglosando cada una de sus partes y sus formas de uso.




Recuerda que aquí tienes el indice de todos los posts del Curso de LinQ.



Vamos a empezar por ver su sintaxis:

                (parametro1, parametro2, …, parámetroN) => bloque de código

Para seguir el hilo, y ya que haremos muchas comparaciones con los métodos anónimos, vamos a continuar con el mismo ejemplo de delegado de la entrada anterior, sobre métodos anónimos, que podemos encontrar aquí link:


public delegate string MiDelegado(string mensaje);

Simplemente un delegado que recibe un parámetro string y que devuelve otra cadena.

Esté podría ser un método al que asignar a la lista de ejecución de este delegado:

public static string AñadirFechaAMensaje(string mensaje)
{
    return string.Format("{0} - {1}", mensaje, DateTime.Now);
}


Nosotros utilizaremos el contenido de este método para emplearlo dentro de nuestros métodos anónimos y Lambdas.


Así sería la asignación de nuestro método anónimo:

MiDelegado miDelegadoAnomimo = delegate(string mensaje)
{
    return string.Format("{0} - {1}", mensaje, DateTime.Now);
};

Y esta sería la misma para la Lambda:

MiDelegado miDelegadoLambda = mensaje => string.Format("{0} - {1}", mensaje, DateTime.Now);


En este gráfico vamos a desglosar las diferencias:


Como podemos observar la utilización de la Lambda, conlleva una reducción considerable de código, en su mayoría precedente de la inferencia de tipos. Vamos a detallar las diferencias:

  • Eliminación de la palabra delegate, referente a los métodos anónimos.
  • Eliminación del tipo de definición del parámetro. La Lambda no necesita indicar el tipo del parámetro ya que lo infiere directamente de la firma del delegado.
  • Eliminación de los paréntesis del parámetro. Como veremos más adelante cuando tenemos un único parámetro en Lambdas, no es necesario añadir los paréntesis.
  • Eliminación de las llaves para el contenido del código de ejecución. Como veremos más adelante, esto tampoco es necesario cuando tenemos una única sentencia para Lambdas.
  • Eliminación de la cláusula return. Igualmente, esto no será necesario, ya que se puede inferir de la firma del delegado, por lo que el compilador comprobará que la sentencia devuelve un dato del tipo de devolución de la firma del delegado.


Por motivos didácticos he utilizado la definición de un delegado para estos ejemplos, pero este paso nos lo podríamos haber saltado utilizando un delegado genérico Func<>:

Func<string, string> miFunc = mensaje => string.Format("{0} - {1}", mensaje, DateTime.Now);


Las Lambdas, tienen una serie de particularidades en su sintaxis:


  • Los paréntesis para indicar los parámetros, solo serán obligatorios cuando nuestra Lambda tenga más de un parámetro. En ningún momento tendremos que indicar el tipo, ya que aunque haya más de uno, este continuará infiriendo el tipo de la firma del delegado por posición de los mismos.


Func<int, int, int> miFunc = (a, b) => a * b;


  • Las llaves correspondientes a la definición del cuerpo de ejecución, solo serán obligatorias, cuando tengamos más de una sentencia:

Action<int, int, int> miAction = (dias, meses, años) =>
{
    DateTime fecha = DateTime.Today;
    fecha.AddDays(dias);
    fecha.AddMonths(meses);
    fecha.AddYears(años);
 
    Console.WriteLine("La nueva fecha es {0}", fecha);
};



Pues con todo esto damos por acabado el paso por las Lambdas, un elemento cada vez más importante dentro del Framework y que se está extendiendo en todas las novedades que se van introduciendo.