Lambda表达式和表达式树

时间:2022-01-15 20:08:51
一: Lambda表达式

首先,表达式的类型本身并非委托类型,但它可以通过多种方式隐式或者显式地转换成一个委托实例。匿名函数这个术语同时涵盖了匿名方法和Lambda,很多情况下两者可以使用相互转换原则。

1.用匿名方法创建委托实例。                     
 Func<string, int> returnlength = delegate(string text) { return text.Length; };
对照的直接用lambda形式实现上述方法,代码如下:
  Func<string, int> returnlength = (string text) => { return text.Length; };
等同于
Func<string, int> returnlength = (string text) => text.Length;
或者
Func<string, int> returnlength = (text) => text.Length;
在阅读lanbda表达式时,可以将 => 部分看成 ”goes to“。

 一: 表达式树

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"));