miércoles, 4 de julio de 2007

Primer aproximación a las expresiones Lambda

Expresiones Lambda, inferencia de tipos, que palabras más raras. Esa fue mi primera impresión cuando las escuche, sobre todo lo de inferencia de tipo, no entendía lo que era una expresión Lambda y en la explicación decia que utiliza inferencia de tipos, en fin, vamos a ver de qué se trata.

List<Persona> personas = new List<Persona>() { new Persona{Nombre="Javier",Apellido="Saviola",Edad=25}, new Persona{Nombre="Enzo",Apellido="Francescoli",Edad=45}, new Persona{Nombre="Pablo",Apellido="Aimar",Edad=28} };
IEnumerable<Persona> mayores= personas.Where(p => p.Edad > 25);
foreach (Persona item in mayores)
{
 ObjectDumper.Write(item);
}


La primer cosa que nos llama la atención de este código es que River Plate no tiene ídolos jóvenes, la segunda es la siguiente línea IEnumerable<persona> mayores= personas.Where(p => p.Edad > 25); Esto es justamtente una expresión Lambda utilizada como parámetro del método Where, y es justo por eso que podemos entender su funcionamiento. Si vamos a la firma del método vemos public static IEnumerable<tsource> Where<tsource>(this IEnumerable<tsource> source, Func<tsource,bool> predicate); Ignoremos el primer parámetro que indica que es un método de extensión, es el segundo el que nos interesa Func<Tsource,bool> predicate El método espera una función con dos parámetros, primero el mismo tipo de la colección (en este caso Persona), y por otro lado un booleano (que será el criterio). Aquí es donde entra la inferencia de tipos, ya que sabemos que el primer parámetro es un objeto Persona y el segundo una expresión que retorna bool simplemente indicamos p=>p.Edad>24 la primer p será el nombre que le damos al primer parámetro (o sea que será el objeto persona) y el segundo la expresión, en este caso evaluamos la edad. Eso es lo que significa inferencia de tipos, todo aquello que se puede suponer (como que el primer parámetro será un objeto Persona) se supone a favor de hacer más fácil el código y no tener que escribir un delegado para esto.

Destripando el código

Sin embargo, esto no es mágia, sino que el compilador crea el delegado por nostros, echemos mano del Reflector y veamos qué onda
private void Test()
{
List<Persona> <>g__initLocal0 = new List();
Persona <>g__initLocal1 = new Persona();
<>g__initLocal1.Nombre = "Javier";
<>g__initLocal1.Apellido = "Saviola";
<>g__initLocal1.Edad = 0x19;
<>g__initLocal0.Add(<>g__initLocal1);
Persona <>g__initLocal2 = new Persona();
<>g__initLocal2.Nombre = "Enzo";
<>g__initLocal2.Apellido = "Francescoli";
<>g__initLocal2.Edad = 0x2d;
<>g__initLocal0.Add(<>g__initLocal2);
Persona <>g__initLocal3 = new Persona();
<>g__initLocal3.Nombre = "Pablo";
<>g__initLocal3.Apellido = "Aimar";
<>g__initLocal3.Edad = 0x1c;
<>g__initLocal0.Add(<>g__initLocal3);
List personas = <>g__initLocal0;
IEnumerable mayores = personas.Where(delegate (Persona p) { return (p.Edad > 0x19); }).Select(delegate (Persona p) { return p; });
foreach (Persona item in mayores)
{
 ObjectDumper.Write(item);
}
}


Vemos en la línea que resalté que ha sido creado un delegado de la expresión Lambda (de echo son dos hay otro para el método Select), esto no lo haremos en la práctica (descompilar cada cosa que hacemos) pero es útil para entender cómo funcionan las cosas. Hasta la próxima.