1.08.2010

Linq y los Árboles de Expresiones ( Expression Trees) – Parte 1

Los árboles de expresiones nos permiten parsear expresiones enviadas a un método. Un árbol de expresiones en Linq es como lo indica su nombre, una estructura de árbol que contiene expresiones. Las expresiones por otra parte, en este caso particular son expresiones Lambda, las cuales como vimos en un post pasado, son una nueva manera de definir un delegate en C#. El árbol de expresiones es una estructura de datos que contiene expresiones lambda compiladas.

Los árboles de expresiones son dinámicos, ya que al igual que los delegates, permiten cambiar en tiempo de ejecución la expresión a ejecutar; es decir, estos árboles son estructuras que contienen expresiones que se utilizan para procesar los datos. Para entender como funcionan los árboles de expresiones vamos a analizar un ejemplo. En primera instancia, vamos a tener una clase Producto.

public class Producto
{
public int Id { get; set; }
public string Nombre { get; set; }
public double Precio { get; set; }

public Producto(int id, string nombre, double precio)
{
Id = id;
Nombre = nombre;
Precio = precio;
}
}



Seguidamente vamos a crear un arreglo de productos y vamos a aplicarle una expresión lambda utilizando un árbol de expresiones.



private static void ApplyFunction()
{
Producto[] productos = {
new Producto(1, "Laptop", 500),
new Producto(2, "Monitor", 300),
new Producto(3, "Zune HD", 230),
new Producto(4, "IPod Touch", 200),
new Producto(5, "Black Berry Storm", 540),
new Producto(6, "Wii", 199)
};

String Message = "";
Expression<Func<Producto, Boolean>> expProductos = miProducto => miProducto.Precio > 299;
foreach (Producto producto in productos)
if (expProductos.Compile().Invoke(producto))
Message = Message + producto.Nombre + "\r\n";
Console.WriteLine(Message);
}


La parte del árbol de expresiones empieza en la parte de la creación de lo que parece un bloque de código complejo. La clase Expression<T> acepta un delegate prototipo como parámetro. El delegate se define usando el delegate genérico Func<T, TResult>. En este caso, el delegate genérico acepta un string como parámetro de entrada y retorna un booleano.Sin embargo, se pueden utilizar cualquier tipo en la entrada o en el retorno que se requiera en la aplicación. La definición de la expresión viene de seguido, expProductos contiene una expresión booleana que recibe un string y devuelve un booleano, el cual es determinado a partir del precio del producto – si es mayor de 99 retorna true, de lo contrario retorna false. En este punto, expProductos contiene una estructura árbol que incluye todos los elementos requeridos para la expresión lambda: miProducto => miProducto.Precio > 299;



Para invocar la función se invoca la expresión utilizando Compile().Invoke(producto) donde se evalúa la variable que se envía por parámetro y se retorna verdadero si cumple con la expresión, o falso si no lo cumple.



En el siguiente post vamos a crear un árbol de expresiones desde 0.



Technorati Tags: ,,

No hay comentarios: