Welcome

首页 / 软件开发 / LINQ / Linq Lambda表达式全面分析

Linq Lambda表达式全面分析2011-08-07 IT168 在向大家详细介绍Linq Lambda表达式之前,首先让大家了解下expr是什么样的东西,然后全面介绍 Linq Lambda表达式。

介绍Linq Lambda表达式之前,先看一个例子:

Expression<Func<string, bool>> expr = o => o.Length > 10;

初次接触Linq Lambda表达式的人可能会被搞迷糊,这样的语句到底是什么意思,怎么样工作,原理又 是什么。

逐级分析以上语句,分为两个部分,以等号为界。

第一部分是变量类型的申明:Expression<Func<string, bool>> expr,表示expr这个变 量是一个Linq Lambda表达式,这个表达式符合这样的一种委托:bool DelegateName(string obj)。

第二部分是表达式的声明o => o.Length > 10,这个“=>”是Lambda操作符,读作“转到” ,必须把=>左右看成是一个整体,因为这实际是一个匿名方法,“=>”左边是方法传入参数的申明 ,右边是函数体,如果用常规的表示方法,可以写成如下形式:

bool MethodName(string o)
{
return o.Length > 10;
}

仔细观察两部分拆解以后的形式其实不难发现,第一部分的工作是定义了一个匿名的委托,而第二部 分则是符合这个匿名委托的一个方法,由于这个方法没有明确给定名称,因此称为匿名方法。

那么,expr到底又是什么样的东西。有一点必须明确的是,expr表示绝对不是这个匿名方法的返回值 ,而是这个匿名方法中所有表达式的 System.Linq.Expressions.Expression形式。也就是说,在expr中 ,这个函数体里所有的表达式已经被拆解成一个一个的单元,每一个单元都是一种 System.Linq.Expressions.Expression的派生类。由于表达式和表达式之前存在着上下级的关系,因此所 有的表达式呈现一种树状结构,称为表达式树。

一个匿名方法是如何转换为表达式树的呢?这个问题其实不用太过关心,因为C#编译器在对程序编译 的时候已经将上述第二部分的内容自动转换为相应的表达式树了。上述例子中编译的结果通过Reflector 反编译出来的内容如下所示:

1. ParameterExpression CS$0$0000;
2. Expression<Func<string, bool>> expr = Expression.Lambda<Func<string,
bool>>(Expression.GreaterThan(Expression.Property(CS$0$0000 = Expression.
Parameter(typeof(string), "o"), (MethodInfo) methodof(string.get_Length)),
Expression.Constant(10, typeof(int))), new ParameterExpression[] { CS$0$0000 });

这串代码看起来有点糊,我把代码梳理了一下使得它更容易读,如下所示:

Expression<Func<string, bool>> expr;

// 创建表示参数的表达式。
ParameterExpression paramExpr = Expression.Parameter(typeof(string), "o");
// 获取表示System.String.Length属性的System.Reflection.PropertyInfo对象。
PropertyInfo propInfo = typeof(string).GetProperty
("Length", BindingFlags.Instance | BindingFlags.Public);
// 创建访问System.String.Length属性的表达式。
MemberExpression memberExpr = Expression.Property(paramExpr, propInfo);
// 创建一个表示常量10的表达式。
ConstantExpression constExpr = Expression.Constant(10, typeof(int));
// 创建表示左边大于右边的二分表达式。
BinaryExpression greaterThanExpr = Expression.GreaterThan(memberExpr, constExpr);
// 通过上述二分表达式创建一个Lambda表达式。
expr = Expression.Lambda<Func<string, bool>>(greaterThanExpr, paramExpr);

是不是好麻烦啊?呵呵,好在这些工作已经在编译的时候完成了,不需要我们手工创建,除非你想动 态创建表达式。关于如何动态创建表达式,我在这里就先不详细说明了,将在下一博里再详述。

综上所述,对待Linq Lambda表达式,最基本一个原则是不要把表达式看成了语句的运算结果,而应该 看成这些语句本身,也就是把语句作为对象来处理。语句和语句之间通过表达式树来关联,而从语句转换 为表达式树已由编译器自动完成,不需要人工介入。