将Lambda表达式转换为表达式树

8

来自《C#深度剖析》:

并非所有 Lambda 表达式都可以转换为表达式树。如果 Lambda 包含一个语句块(即使只有一个返回语句),则无法将其转换为表达式树。表达式必须具有仅求值单个表达式的形式。

由于 Linq-to-Object 语句不会被转换为表达式树对象,因此与 Linq-to-Object 操作符一起使用的 Lambda 表达式可以包含一个语句块。

        string[] count = { "one ", "two ", "three ", "four ", "five ", "six " };
        IEnumerable<int> result = count.Select(item =>
                               {
                                   Console.WriteLine(item);
                                   return item.Length;
                               });
        foreach (int i in result);

输出:

one two three four five six

我还没有开始学习Linq-To-Sql或Linq-To-Entities,但我认为与操作>的LINQ语句一起使用的lambda表达式只能包含一个表达式,因为只有一个表达式可以转换为表达式树的限制。谢谢。
2个回答

18

它不仅仅只能包含一个表达式 - 它根本不能成为一个语句lambda。即使是像这样的一个块:

var result = query.Select(item => { return item.Length; });

这个表达式在 LINQ to SQL 中是无效的。它必须改写为:

var result = query.Select(item => item.Length);

我刚刚注意到这正是你引用的那本书中的内容。好吧-这说明我很一致 :)

需要注意的是,从.NET 4开始,表达式树本身确实有包含块的能力,但是C#编译器无法将语句lambda转换为那种表达式树。还有其他限制,但它们很少引起问题。

这在C# 4规范的第4.6节中有明确说明:

并非所有匿名函数都可以表示为表达式树。例如,具有语句主体和包含赋值表达式的匿名函数不能表示。在这些情况下,仍然存在一种转换,但在编译时会失败。


8
你究竟对《C#深入研究》中提到的东西了解多少呢?算了,不用管了。 - Patrick Karcher
@Jon:我突然想到这个问题与http://stackoverflow.com/questions/8405423/do-at-compile-time-linq-to-objects-statements-also-get-translated-into-expressio非常相关,*眨眼* - AspOnMyNet
Jon,当你说它不能是语句 lambda 时,你的意思是什么?该问题展示了使用语句 lambda 的样例代码,并输出了正确的值。 - Nick
@Nick:它使用一个语句lambda... 但将其转换为委托,而不是表达式树。 - Jon Skeet
表达式树不执行代码,而是生成数据,稍后可以将其编译回代码。 - Azri Jamil
@wajatimur:我不太确定你的评论的意图是什么...你能解释一下吗? - Jon Skeet

1

你是对的,它们只能包含一个表达式。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接