Expression类的用途是什么?

问题描述:

我想知道包装内Expression<>而不是代表之间的区别究竟是什么?Expression类的用途是什么?

我看到Expression<Foo>被Linq使用了很多,但到目前为止我还没有找到任何解释这种差异和仅仅使用委托的文章。

E.g.

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

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

通过将lambda作为委托存储,您正在存储执行某个操作的委托的特定实例。它不能被修改,你只需要调用它。一旦你有了你的委托,你在检查它的作用和内容方面的选择有限。

通过将lambda作为表达式存储,您正在存储表示代表的表达式树。它可以被操纵来做其他事情,比如改变它的参数,改变身体并使它做一些完全不同的事情。它甚至可以编译回代表,所以如果你愿意,你可以调用它。你可以很容易地检查表达式,看看它的参数是什么,它做了什么以及它是如何做的。这是查询提供程序可用于理解表达式并将其转换为其他语言(如为相应的表达式树编写SQL查询)的内容。

使用表达式动态创建代理比发出代码更容易。您可以将代码视为更高级别的表达式,这与表达式与编译器查看代码的方式非常相似,而不是低级别,并将您的代码视为IL指令。

所以对于一个表达式,你可以做的远不止一个简单的匿名委托。虽然它不是真正免费的,但如果您运行编译的表达式与常规方法或匿名代理相比,性能会受到影响。但是这可能不是一个问题,因为使用表达式的其他好处对您而言可能很重要。

+0

这对我来说很完美,非常感谢:-) – Steffen

Func<>只是一个委托类型。一个表达式,一个operations完整树的运行时表示,它可以选择性地在运行时编译成一个委托。它是由像Linq-to-SQL这样的表达式解析器进行解析来生成SQL语句或执行其他聪明事情的树。当您将lambda分配给Expression类型时,编译器会生成此表达式树以及通常的IL代码。 More on expression trees

提供从中派生出代表 表达式树节点的类的基类。

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

表达树表示可以被分析,并且例如变成SQL查询LINQ表达式。

Expression Trees允许您在代码中检查表达式内部的代码。

例如,如果您通过了以下表达式:o => o.Name,您的代码可能会发现Name属性在表达式内被访问。

为了说明其他的答案,如果你编译那些2倍的表达,并在编译器生成的代码有看,这我你会看到什么:

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

好的,你试图创建什么点? – Phil

+4

他在问什么是差异,生成的代码是不言自明的差异。 – Ucodia

无论其他人写什么(这是完全正确的),我会通过Expression类添加,您可以在运行时创建新方法。有一些限制。并非所有在C#中可以做的事情都可以在Expression树中完成(至少在.NET 3.5中,使用.NET 4.0,他们已经添加了大量可能的Expression“类型”)。使用它可以(例如)创建一个动态查询并将其传递给LINQ-to-SQL,或者根据用户的输入做一些过滤......(如果你想要的话你可以使用CodeDom来做到这一点是一种与LINQ-to-SQL不兼容的动态方法,但是直接发送IL代码是相当困难的:-))