2016-08-17 50 views
0

这是代码。是什么让C#编译器输出表达式树而不是代码?

int[] data = new int[] { 1, 2, 3, 4, 5 }; 
    var q1 = data.Select(x => 10 * x); 
    var q2 = data.AsQueryable().Select(x => 10 * x); 
    Expression<Func<int,int>> qe = (x) => 10 * x; 

在第一种情况下,编译器生成评估表达式的代码。输出中没有表达式树。

它在第二次生成表达式树(在调试时可见),它在运行时被编译并执行以执行查询(并且执行完全相同的操作)。

在第三种情况下,直接创建与(2)相同的lambda作为表达式树(而不是代码)。

在这两种情况下,什么使编译器生成表达式树而不是代码,还有其他有趣的情况吗?

原因:我想在运行时“分离”表达式树的顶层,然后编译并执行较低层。我无法让编译器按我的方式做事!

+2

这是“编译器如何编写”的一个例子。它需要这样做才能使表达式工作。这就好像返回'IEnumerable '的方法''可以使用'yield return'。支持语言功能的特殊编译器操作。 – Enigmativity

+0

名单继续。编译器会以不同的方式处理'Nullable '类型。它可以为'foreach'循环使用duck-typing。 LINQ查询实际上只是重新排列的方法(通常是扩展方法,但不需要)。 “使用”陈述仅适用于一次性用品等。 – Enigmativity

+0

您的第一个陈述并非真正的表达;它是一个*构造函数调用。*两个Select语句是Linq语句,它们作为其正常操作的一部分生成表达式。第四个语句生成一个表达式,因为您将表达式指定为结果类型。 –

回答

3

EnumerableSelect方法接受Func<TSource,TResult>类型的参数。 QueryableSelect方法接受类型为Expression<Func<TSource,TResult>>的参数。

就这么简单 - 如果编译器有一个lambda表达式,它可以生成一个表达式或编译lambda表达式,这个决定是基于它被要求创建的 - 如果它是某种类型的Expression,它将生成表达式树。如果它是Func或其他委托类型,它将生成代码。

+0

该死!这真的很简单!如果参数派生自Delegate,则编译器会生成代码,如果派生自Expression,则编译器会生成代码,并且没有其他选择。谢谢! –

+1

请记住,代表可以跨越多行,但表达式树的写法与代表相同,例如, '表达式> lambda =()=> new int [] {1,2,3,4,5};'只能是一行。 – Sagi