2011-10-14 9 views
43

Me pregunto cuál es exactamente la diferencia entre envolver a un delegado dentro de Expression<> y no?¿Cuál es el propósito de la clase Expression?

Estoy viendo que Expression<Foo> se usa mucho con LinQ, pero hasta ahora no he encontrado ningún artículo que explique la diferencia entre esto, y solo el uso de un delegado.

E.g.

Func<int, bool> Is42 = (value) => value == 42; 

vs

Expression<Func<int, bool>> Is42 = (value) => value == 42; 

Respuesta

48

Al almacenar un lambda como delegado, está almacenando una instancia específica de un delegado que realiza alguna acción. No se puede modificar, solo lo llamas. Una vez que tenga a su delegado, tiene opciones limitadas para inspeccionar lo que hace y lo que no.

Al almacenar una lambda como expresión, está almacenando un árbol de expresiones que representa al delegado. Puede ser manipulado para hacer otras cosas como cambiar sus parámetros, cambiar el cuerpo y hacer que haga algo radicalmente diferente. Incluso podría compilarse de nuevo a un delegado para que pueda llamarlo si lo desea. Puede inspeccionar fácilmente la expresión para ver cuáles son sus parámetros, qué hace y cómo lo hace. Esto es algo que un proveedor de consultas puede usar para comprender y traducir una expresión a otro idioma (como escribir una consulta SQL para un árbol de expresiones correspondiente).

También es mucho más fácil crear un delegado dinámicamente utilizando expresiones de las que emite el código. Puede pensar en su código en un nivel superior como expresiones que es muy similar a cómo un compilador ve el código en lugar de ir a bajo nivel y ver el código como instrucciones IL.

Así que con una expresión, usted es capaz de hacer mucho más que un simple delegado anónimo. Aunque no es realmente gratis, el rendimiento tendrá éxito si ejecuta expresiones compiladas en comparación con un método regular o un delegado anónimo. Pero eso podría no ser un problema ya que los otros beneficios de usar expresiones pueden ser importantes para usted.

+0

Esto lo aclaró perfectamente para mí, muchas gracias :-) – Steffen

13

Func<> es sólo un tipo de delegado. Una Expresión una representación en tiempo de ejecución del árbol completo de operations que, opcionalmente, puede compilarse en tiempo de ejecución en un delegado. Es este árbol analizado por los analizadores de expresiones como Linq-to-SQL para generar sentencias de SQL o hacer otras cosas inteligentes. Cuando asigna un lambda a un tipo de Expresión, el compilador genera este árbol de expresiones, así como el código IL habitual. More on expression trees.

4

Proporciona la clase base a partir de la cual se derivan las clases que representan los nodos del árbol de expresiones .

System.Linq.Expressions.BinaryExpression 
System.Linq.Expressions.BlockExpression 
System.Linq.Expressions.ConditionalExpression 
System.Linq.Expressions.ConstantExpression 
System.Linq.Expressions.DebugInfoExpression 
System.Linq.Expressions.DefaultExpression 
System.Linq.Expressions.DynamicExpression 
System.Linq.Expressions.GotoExpression 
System.Linq.Expressions.IndexExpression 
System.Linq.Expressions.InvocationExpression 
System.Linq.Expressions.LabelExpression 
System.Linq.Expressions.LambdaExpression 
System.Linq.Expressions.ListInitExpression 
System.Linq.Expressions.LoopExpression 
System.Linq.Expressions.MemberExpression 
System.Linq.Expressions.MemberInitExpression 
System.Linq.Expressions.MethodCallExpression 
System.Linq.Expressions.NewArrayExpression 
System.Linq.Expressions.NewExpression 
System.Linq.Expressions.ParameterExpression 
System.Linq.Expressions.RuntimeVariablesExpression 
System.Linq.Expressions.SwitchExpression 
System.Linq.Expressions.TryExpression 
System.Linq.Expressions.TypeBinaryExpression 
System.Linq.Expressions.UnaryExpression 

http://msdn.microsoft.com/en-us/library/system.linq.expressions.expression.aspx

árbol de expresión representa la expresión LINQ que pueden ser analizados y, por ejemplo, se convirtió en la consulta SQL.

4

Expression Trees le permiten inspeccionar el código dentro de la expresión, en su código.

Por ejemplo, si pasó esta expresión: o => o.Name, su código podría descubrir que se estaba accediendo a la propiedad Name dentro de la expresión.

9

Para ilustrar otras respuestas, si compila las 2 expresiones y tienen vistazo al código del compilador generado, esto lo verá:

Func<int, bool> Is42 = (value) => value == 42;

Func<int, bool> Is42 = new Func<int, bool>((@value) => value == 42); 


Expression<Func<int, bool>> Is42 = (value) => value == 42;

ParameterExpression[] parameterExpressionArray; 
ParameterExpression parameterExpression = Expression.Parameter(typeof(int), "value"); 
Expression<Func<int, bool>> Is42 = Expression.Lambda<Func<int, bool>>(Expression.Equal(parameterExpression, Expression.Constant(42, typeof(int))), new ParameterExpression[] { parameterExpression }); 
+0

Ok, qué punto tratas de hacer ? – Phil

+4

Preguntaba cuáles eran las diferencias y el código generado se explicaba por sí mismo de las diferencias. – Ucodia

2

Para lo que haya escrito el otro (eso es completamente correcto) agregaré que a través de la clase Expression puede crear nuevos métodos en tiempo de ejecución. Hay algunos límites. No todas las cosas que puede hacer en C# se pueden hacer en un árbol Expression (al menos en .NET 3.5. Con .NET 4.0 han agregado una gran cantidad de posibles "tipos" Expression). El uso de esto podría ser (por ejemplo) para crear una consulta dinámica y pasarla a LINQ-to-SQL o hacer algún tipo de filtrado basado en la entrada del usuario ... (siempre podría hacer esto con CodeDom si todo lo que deseaba era un método dinámico incompatible con LINQ-to-SQL, pero emitir directamente el código IL es bastante difícil :-))

Cuestiones relacionadas