摘要:[原文作者]: Timothy Ng
[原文链接]: Lambda Expressions and Expression Trees
大家好,我是Tim, 是VB编译器组的组长。最近Amanda极力劝说我到VB组的博客上而不是我自己的博客上发表文章。所以我现在就在这里写了。我现在的计划是将与VB有关的文章贴在这,更多关于功能实现/技术/有趣的东西放到我自己的博客上 (比如,那些和VB语言/特性 无关的东西)
最近我的关于Lambda表达式的文章被发表在MSDN杂志上。在此篇文章中,我将那篇文章中的某些理念做一个拓展。如果你们对这篇文章中有什么不理解的,尽可以参考那篇文章。
Lambda表达式非常cool不但是因为那篇文章中所说的原因,而且我们还可以从可读性很强的表格中获取Lambda表达式的内容,就像是在看数据一样,而不是可执行代码。比如,下面这行代码将一个lambda表达式转换为一个可调用委托:
Dim f As Func(Of Integer, Integer) = function(x) x * 2
Dim r = f(10)
这个示例的第一行生成一个Lambda表达式,并将其奇迹般地赋给一个可调用委托f,第二行调用f, 并返回值20.
这非常酷,我的文章将说明,为什么我认为它很酷。其实有更酷的,那就是事实上你可以将Lambda表达式赋给特殊变量类型,而编译器会帮你做很神奇的处理:
Dim e As Expression(Of Func(Of Integer, Integer)) = function(x) x * 2
在这个代码示例中,e不是一个可调用委托,而是表达式树。表达式树是lambda表达式的一种数据表示形式,它能使你更方便地读取和推断Lambda表达式。
如果你深入探究调试器里的e的值,你会很容易地发现表达式是整型变量x与整型常量2的乘积操作。
默认情况下,拓展了Ienumerable接口的表达式能被赋给Lambda表达式;而拓展了Iqueryable接口的查询表达式只能被表达式树赋值。因此,当你生成一个带IQueryable类型查询的时候,编译器将生成一个表达式树而不是Lambda表达式。
在这个问题上,我组里的一个开发人员,Scott,曾经写过一篇很好的文章。他在那篇文章里用了非常好的图表来表现说明一些Lambda树的表达式树表示形式。
你能用表达式树做些什么呢?
大致上,你可以做两件事:
1. 推断表达式树内数据,并对它做自定义处理。你也能将表达式树中的数据转换到其他的域的数据形式(如XML).
2. 用 .Compile() 方法去将一个表达式树转换为一个委托,然后你可以执行它。
3. 编译包含动态条件的查询:参考Jonathan’s的文章,写的非常好的。他举出了大量的例子告诉你如何巧妙地处理那些表达式树和编译你的带自定义条件的lambda表达式。
其中第二条是很有趣的,因为它意味着你能将一个lambda表达式复制进一个表达式树,推断它,并将它转换为一个可调用委托。
Dim e As Expression(Of Func(Of Integer, Integer)) = function(x) x * 2
Dim f = e.Compile
Dim r = f(10)
在这个示例中,变量r的值是20,和我们之前举的将lambda表达式直接赋给一个委托类型得到的结果一样。
这个为什么说它有趣呢?
没有表达式树的话,我们是不可能用描述格式来表示一个表达式的。他们唯一的表示方式是IL (中间语言), 这种语言对于重新表述用户的意图来说太低层次了。然后,表达式树对一个表达式提供了一个高级的树表示方式来表现表达式,这样你就能很容易地理解用户的该表达式的意图。
如下是一些可能比较有趣的表达式树的用法:
1. 推断表达式,然后将他们转换为委托并调用他们;
2. 将表达式转换为SQL, 这样他们就能被服务器执行了 (这是linq到sql所做的工作)
3. 将表达式转换为XML并将他们写到磁盘上;
4. 将表达式转换为自定义形式并将他们通过某种网络协议发送到能将之通过某种格式重编译为表达式树,重新生成表达式分析并执行他们的服务器上。
在后面的几篇文章中,我将特别讲述关于VB编译器生成的表达式树,以及VB树与C#树之间的区别以支持VB同语义学。
我也将对你们能做的事情给出一些小技巧,这样任何你们所写的用到表达式树的类库将为VB开发程序员提供最好的体验。...[
阅读全文]