后续所有文章都以短文形式来阐述,若为长文将分为多篇分开讲解,同时代码将沿袭最近文章所示而非截图,相信通过如此改善能较好提高阅读体验。
有一部分童鞋对lambda表达式并不是十分了解和清楚,比如说说如下二者的区别在哪里?
Func<int, int> code = x => x + 1;
Expression<Func<int, int>> data = x => x + 1;
在完成上述分配后,我们了解到委托和表达式都可以表达lambda表达式,二者的区别在于通过委托表示引用返回x+1的方法,表达式树引用描述表达式x=>x+1的数据结构
通过委托表示的表达式是可执行代码,通过表达式树是数据结构,也就是说表达式可通过可执行代码和数据结构来表示。
表达式树允许将lambda表达式表示为数据结构而不是可执行代码,表达式树是形式为System.Linq.Expressions.Expression<D>的表达式树类型的值,其中D是任何委托类型。
如果存在从lambda表达式到委托类型D的转换,则也存在到表达式树类型Expression<D>的转换,将lambda表达式转换为委托类型会生成引用了lambda表达式的可执行代码的委托,而转换为表达式树类型则会创建lambda表达式的表达式树表示形式。
表达式树是lambda表达式的有效内存数据表示形式,并使lambda表达式的结构透明且显式。就像委托类型D一样,Expression<D>据说具有参数和返回类型,与D相同。
表达式树提供了实例方法Compile,该方法将编译生成类型为D的委托,也就是说将所描述的数据结构通过此方法编译成可执行的代码,如下:
Expression<Func<int, int>> data = x => x + 1;
Func<int, int> exp = data.Compile();
var result = exp(1);
Console.WriteLine(result);
并非所有的lambda表达式都可转换为表达式树,在如下情况下,转换仍然存在,但在编译时将失败。
有块体
Expression<Func<int, int>> data = x => { return x + 1 };
包含简单或复合赋值运算符
Expression<Func<int, int>> data = x => x++;
包含动态绑定的表达式
Expression<Func<int, int>> data = x => (dynamic)x + 1;
异步表达式
Expression<Func<int, Task<int>>> data = async x => x + 1;
并非所有的lambda表达式都可转换为委托类型,比如如下存在类型转换错误
Func<double, int> code = x => x + 1;
很显然编译时出现错误,因为当x的类型为double类型时,x +1的结果(double类型)不能隐式转换为int类型。
如上匿名异步函数不可转换为表达式树,但可转换为委托类型,因为x +1的结果(类型为int)可以隐式转换为任务类型Task<int>的结果类型int
Func<int, Task<int>> code = async x => x + 1;