表达式树





4.00/5 (5投票s)
表达式树
什么是表达式树?
表达式不像其他代码,更像一种二叉树数据结构,其中每个节点代表一个对象及其子节点。表达式树可以从 Lambda 表达式中派生,你可以在框架类中很容易地看到这一点。表达式树的一个很好的理由是它允许创建动态 LINQ 查询。
Expression 类
using System.Collections.ObjectModel; namespace System.Linq.Expressions { // Summary: // Represents a strongly typed lambda expression as a data structure in the // form of an expression tree. This class cannot be inherited. // // Type parameters: // TDelegate: // The type of the delegate that the System.Linq.Expressions.Expression<tdelegate> // represents. public sealed class Expression<tdelegate> : LambdaExpression { // Summary: // Compiles the lambda expression described by the expression tree into executable // code. // // Returns: // A delegate of type TDelegate that represents the lambda expression described // by the System.Linq.Expressions.Expression<tdelegate>. public TDelegate Compile(); } } </tdelegate></tdelegate></tdelegate>
Expression 的语法
Expression<Func<type,returnType>> = (param) => lamdaexpresion;
命名空间 System.Linq.Expressions;
包含表达式树类的定义。因此,在使用 Expression 类之前,你需要包含此命名空间。
示例
Expression<Func<int,int, int>> lambda = (a,b) => a * b;
对于上述表达式的表达式树
安装表达式树可视化工具
如果你没有可视化工具来查看表达式树,可以按照以下说明进行安装:
下载示例:http://code.msdn.microsoft.com/csharpsamples
编译代码:Official_Visual_Studio_2008_C#_Samples\ExpressionTreeVisualizer\C#\ExpressionTreeVisualizer\
从以下位置获取 Dll:
bin\Debug\expressionTreeVisualizer.dll
将 Dll 安装到路径:C:\Program Files\Microsoft Visual Studio 9.0\Common7\Packages\Debugger\Visualizers
表达式树的组成部分
表达式树由以下部分组成,每个部分在下面的图像中显示。
正文
参数
表达式的 NodeType 和 Type
Lambda 表达式和 Expression 之间的区别
在上面的例子中,我将 lambda 表达式赋值给 Expression 类型,这样做环境会将 lambda 表达式表示为表达式树,而不是 lambda 表达式。如果你查看表达式树的内存表示,它是一个表达式的对象表示,这与 lambda 表达式的 IL 不同,你可以在表达式树可视化工具中看到。
当你编写
Func<int,int, int> lambdaExpression = (a,b) => a * b;这是一个 lambda 表达式。
需要注意的重要一点是:
你不能使用带有语句的 lambda 表达式来创建表达式树
Expression<Func<int, int, bool>> IsAGreater = (a, b) => { if (a > b) return true; else return false; };
上面的代码会在编译时引发错误。
如何创建表达式树?
第一种方法
第一种方法很简单,我已经上面讨论过:“创建 Lambda 表达式并将其赋值给 Expression。”
Expression<Func<int,int, int>> lambda = (a,b) => a * b;
就像上面一样。
第二种方法
要创建表达式,你需要按以下步骤逐一进行。我也会展示可以在动态表达式中使用的函数。
private void CreateExpressionTree() {为表达式创建参数。
ParameterExpression exp1 = Expression.Parameter(typeof(int), "a"); ParameterExpression exp2 = Expression.Parameter(typeof(int), "b");创建表达式的主体,在此示例中,使用 multiply 函数获取两个参数的乘积。
BinaryExpression exp = Expression.Multiply(exp1,exp2); var lamExp = Expression.Lambda<Func<int, int, int>> (exp, new ParameterExpression[] { exp1, exp2 });Compile 方法编译表达式树,Invoke 允许执行编译后的表达式树。如你所见,你需要传递表达式树参数的值。
int c = (lamExp.Compile()).Invoke(2,5); Response.Write(c); }
表达式树的应用?
我发现表达式树的一个应用是利用表达式来构建动态 LINQ 查询。
示例 1: - 绑定查询以获取数据并动态排序数据。如你所见,在下面的代码中,我通过传递 people 对象中的属性名称来构建查询并排序数据。在示例中,使用了 Email 属性进行排序,可以替换为 Name 属性。
private void BindAndSort() { List<people> people = new List<people> { new People(){ Name = "Pranay",Email="pranay@test.com",CityID=2 }, new People(){ Name = "Heamng",Email="Hemang@test.com",CityID=1 }, new People(){ Name = "Hiral" ,Email="Hiral@test.com",CityID=2}, new People(){ Name = "Maitri",Email="Maitri@test.com",CityID=1 } }; ParameterExpression param = Expression.Parameter(typeof(People), "People"); Expression ex = Expression.Property(param, "Email"); var sort= Expression.Lambda<Func<People, object>>(ex, param); var sortedData = (from s in people select s).OrderBy<people, object>(sort.Compile()).ToList<people>(); GridViewNotional.DataSource = sortedData; GridViewNotional.DataBind(); }示例 2: - 构建查询以使用 Email 属性从 people 实体搜索数据,并且 Email 以“h”开头。在这里,属性可以替换为 Name 属性。
ParameterExpression param = Expression.Parameter(typeof(People), "People"); Expression ex = Expression.Property(param, "Email"); // Get the method information for the String.StartsWith() method MethodInfo mi = typeof(String). GetMethod("StartsWith", new Type[] { typeof(String) }); MethodCallExpression startsWith = Expression.Call(ex, mi, Expression.Constant("h")); Expression<Func<People, bool>> expression = Expression.Lambda<Func<People, bool>>(startsWith, param); var searchData = (from s in people select s).Where(expression.Compile()).ToList<people>(); </people>示例 1 和示例 2 中的方法都可以用泛型替换。