Welcome to Kartones.Net Sign in

Características de C# 3.0 – Expresiones Lambda

En el artículo anterior comenté el diseño de una pequeña librería para implementar las reglas de un RPG. Desde ese día he realizado pequeños cambios en el código con el objetivo de simplificarlo y aumentar el rendimiento. En este artículo (y el próximo) voy a hablar de algunas características nuevas de C# 3.0 que permiten que nuestra librería sea mucho más flexible.

En C# 3.0 la gente de Microsoft añadió muchas mejoras en el lenguaje, la mayoría inspirada en los lenguajes funcionales como Lisp, OCaml,… En particular hay dos que van de la mano: las expresiones lambda y los árboles de expresiones. Este primer artículo va a tratar de las expresiones lambda, así que recordemos que era un delegado y poco a poco veremos el porqué se añadieron todas estas nuevas características a C#.

Por ejemplo, queremos filtrar una lista de elementos T en base a un criterio pero queremos que el criterio sea modificable. Este “criterio” es una función que recibirá un T y devolverá un booleano indicando si el elemento cumple el criterio o no. En código tradicional de C# esto sería un delegado y sería algo como lo que sigue:

delegate bool Criteria<T>(T element);

 

class Program

{

    static List<T> FilterList<T>(List<T> list, Criteria<T> criteria)

    {

        List<T> newList = new List<T>();

        foreach (T element in list)

            if (criteria(element))

                newList.Add(element);

 

        return newList;

    }

 

    static bool CriteriaLessThan5(int intValue)

    {

        return intValue < 5;

    }

 

    static bool CriteriaBiggerThan5(int intValue)

    {

        return intValue > 5;

    }

 

    static void Main(string[] args)

    {

        List<int> numbers = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9 };

        List<int> numbers2;

 

        numbers2 = FilterList(numbers, CriteriaLessThan5);

        foreach (int number in numbers2)

            Console.WriteLine(number);

 

        numbers2 = FilterList(numbers, CriteriaBiggerThan5);

        foreach (int number in numbers2)

            Console.WriteLine(number);

 

        Console.ReadKey();

    }

}

Si os fijáis he declarado un delegado (Criteria) que recibe un elemento T y devuelve bool. Luego he añadido una función FilterList que recibe una lista y un criterio y devuelve la lista filtrada y por último en el main he usado dos funciones diferentes para filtrar una misma lista de números.

A partir de C# 2.0 se añadió al lenguaje la capacidad de declarar delegados anónimos (al vuelo). Usando delegados anónimos el código anterior tendría la siguiente pinta:

delegate bool Criteria<T>(T element);

 

class Program2

{

    static List<T> FilterList<T>(List<T> list, Criteria<T> criteria)

    {

        List<T> newList = new List<T>();

        foreach (T element in list)

            if (criteria(element))

                newList.Add(element);

 

        return newList;

    }

 

    static void Main(string[] args)

    {

        List<int> numbers = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9 };

        List<int> numbers2;

 

        numbers2 = FilterList(numbers, delegate(int e) { return e < 5; });

        foreach (int number in numbers2)

            Console.WriteLine(number);

 

        numbers2 = FilterList(numbers, delegate(int e) { return e > 5; });

        foreach (int number in numbers2)

            Console.WriteLine(number);

 

        Console.ReadKey();

    }

}

Ahora los delegados están metidos directamente en la llamada al método FilterList. En C# 3.0 se añaden las expresiones lambda que es una forma más “bonita” de escribir lo mismo. Además se añaden los delegados genéricos Action y Func que nos ahorran tener que declarar delegados propios. Con lo que en C# 3.0 nuestro código quedaría así:

class Program3

{

    static List<T> FilterList<T>(List<T> list, Func<T, bool> criteria)

    {

        List<T> newList = new List<T>();

        foreach (T element in list)

            if (criteria(element))

                newList.Add(element);

 

        return newList;

    }

 

    static void Main(string[] args)

    {

        List<int> numbers = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9 };

        List<int> numbers2;

 

        numbers2 = FilterList(numbers, e => e < 5);

        foreach (int number in numbers2)

            Console.WriteLine(number);

 

        numbers2 = FilterList(numbers, e => e > 5);

        foreach (int number in numbers2)

            Console.WriteLine(number);

 

        Console.ReadKey();

    }

}

Fijaos cómo ahora ya no se declara ningún delegado “Criteria” porque FilterList recibe un Func<T, bool>, es decir, un delegado genérico que tiene un parámetro T y devuelve un bool. Y además hemos sustituido en la llamada a FilterList lo de “delegate(int e)…” por una expresión lambda (=>) que recibe un “e” y devuelve si ese “e” es menor o mayor que 5 (el compilador automáticamente infiere que “e” tiene que ser de tipo int).

En el próximo artículo veremos como se relacionan las expresiones lambda con los árboles de expresiones, que nos permiten generar y modificar código de forma dinámica dentro del propio programa (código como datos, algo bastante común en los lenguajes funcionales) y la utilidad que tiene esto en una librería para implementar RPGs.



Comments

# re: Características de C# 3.0 – Expresiones Lambda

Monday, March 16, 2009 10:30 AM by Kartones

Cojonuda explicación, si señor, más claro que el agua :D

Por mi sigue que me viene estupendo para leer ultra-resúmenes en lugar de tutoriales tochos.

PD: Al final me picarás para hacer un rpg xD

# re: Características de C# 3.0 – Expresiones Lambda

Monday, March 16, 2009 8:36 PM by Vicente

Me alegro que te haya gustado! :) El proximo yo creo que va a ser mucho mas interesante ya que de arboles de expresiones tampoco hay mucho por internet y son la leche de potentes.

Al final liamos tambien a flipper y hacemos un kartones.net RPG :p

# Árboles de Expresiones

Monday, March 30, 2009 11:03 PM by Jad Engine Blog

Ahora que ya hemos visto que es una expresión lambda podemos ver otra nueva característica mucho más

Leave a Comment

(required ) 
(required ) 
(optional )
(required ) 

Captcha