Lambda表达式和表达式树
首先,表达式的类型本身并非委托类型,但它可以通过多种方式隐式或者显式地转换成一个委托实例。匿名函数这个术语同时涵盖了匿名方法和Lambda,很多情况下两者可以使用相互转换原则。
Func<string, int> returnlength = delegate(string text) { return text.Length; };
Func<string, int> returnlength = (string text) => { return text.Length; };
Func<string, int> returnlength = (string text) => text.Length;
Func<string, int> returnlength = (text) => text.Length;
一: 表达式树
1.1基本知识
表达式树提供了一种抽象的方式将一些代码表示成一个对象树,表达式树主要用于LINQ,树中的每个节点本身都是一个表达式。
不同的表达式类型代表能在代码中执行的不同操作:二元操作,一元操作,方法调用,构造函数调用等等。
System.Linq.Expressions命名空间包含了代表表达式的各个类,它们都继承自Expression,一个抽象的主要包含一些静态工厂方法的类,这些方法用于创建其他表达式类的实例,然而,Expression类也包括两个属性。
1.Type属性代表表达式求值后的.NET类型,可把它视为一个返回类型。例如一个表达式要获取一个字符串的Length属性,该表达式的类型就是int。
2.NodeType属性返回所代表的表达式的种类。它是ExpressionType枚举的成员,包括LessThan、Multiply和Invoke等。仍然使用上面的例子,对于myString.Length这个属性访问来说,其节点类型是MemberAccess。。
并且该属性能区分由相同的类表示的不同种类的表达式。
示例如下:
Expression first = Expression.Constant(2); Expression second = Expression.Constant(3); Expression add = Expression.Add(first, second);
Func<int> acmpiled = Expression.Lambda<Func<int>>(add).Compile(); //编译成可执行的委托方法。
Debug.Write(add);
该代码会产生输出“(2+3)”,这意味着这些表达式树类覆盖了ToString来产生可读的输出。
注意:“叶”表达式在代码中是最先创建的,我们需要自上而下构建这些表达式。
1.2表达式树与委托
LambdaExpression是从Expression派生的类型之一,泛型类 Expression<TDelegate>又是从LambdaExpression派生的。Expression与 Expression<TDelegate>的区别在于:泛型类以静态类型的方法标识了它是什么种类的表达式,也就是说,他确定了返回类型和参数。所以显然,TDelegate必须是一个委托类型。
注意:并非所有的Lambda表达式都能转换成表达式树。不能将带有一个语句块(即使只有一个return语句)的Lambda转换成表达式树,只有对单个表达式进行求值的lambda才可以。表达式中不能包含赋值操作,因为在表达式中表示不了这种操作。
示例二如下:
Expression<Func<string, string, bool>> expression = (x, y) => x.StartsWith(y); Func<string, string, bool> complied = expression.Compile(); Debug.Write(complied("first", "second")); Debug.Write(complied("first", "fir"));
示例二等同于如下代码:
//构造调用方法的各个组件 MethodInfo method = typeof(string).GetMethod("StartsWith", new[] { typeof(string) }); //方法 ParameterExpression target= Expression.Parameter(typeof(string), "x"); //方法主 var methodArg = Expression.Parameter(typeof(string), "y"); //参数 Expression[] methodArgs = new [] { methodArg }; //参数列表 MethodCallExpression call = Expression.Call(target, method, methodArgs); //从以上组件创建CallExpression //将call转换为lambda表达式 ParameterExpression[] lambdaParameters = new[] { target, methodArg }; //参数 var lambda = Expression.Lambda<Func<string, string, bool>>(call, lambdaParameters); Func<string, string, bool> complied = lambda.Compile(); Debug.Write(complied("first", "second")); Debug.Write(complied("first", "fir"));