65.9K
CodeProject 正在变化。 阅读更多。
Home

表达式树

starIconstarIconstarIconstarIconemptyStarIcon

4.00/5 (5投票s)

2012年11月9日

CPOL

3分钟阅读

viewsIcon

34040

表达式树


什么是表达式树?

表达式不像其他代码,更像一种二叉树数据结构,其中每个节点代表一个对象及其子节点。表达式树可以从 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 中的方法都可以用泛型替换。
© . All rights reserved.