我可以控制.NET编译器自动转换为表达式的内容

时间:2013-04-13 19:16:14

标签: vb.net linq compiler-construction

VB编译器自动将lambda转换为LambdaExpression等价物(例如Dim a As LambdaExpression = Function(x) x.Length)。直到最近,我还认为功能应用于lambdas,但后来我尝试将方法调用的结果作为参数传递给方法时发现了相同的行为。编译器将我的调用转换为MethodCallExpression而不是拨打电话!

Dim myQuery = From x In DataSource.Items
              Group By x.Key Into g = Group
              Select New With {
                  .Key = Key,
                  .RedItems = g.Sum(ItemsOfColor(Colors.Red))
              }

Private Function ItemsOfColor(color As Integer) As Expression(Of Func(Of Item, Integer))
    Return Function(item) If(item.Color = color, 1, 0)
End Function

RedItems包含一个MethodCallExpression来调用ItemsOfColor Colors.Red作为参数,而不是LambdaExpression 结果我预期的ItemsOfColor电话。

问题:为什么编译器认为这是我想要的行为,是否有任何方法可以将其关闭?

注意:这是一系列中的第三个问题,它慢慢帮助我理解LINQ的编译方式及其副作用。部分onetwo

1 个答案:

答案 0 :(得分:0)

我想我终于明白了这个问题...所以这里有。查询表达式语法(如上所示)使显示 .RedItems = g.Sum(ItemsOfColor(Colors.Red))是正常的方法调用,但它不是。那个“调用”实际上位于前一行Select语句的lambda体内。用lambda语法重写,这将是:

.Select(Function(x) New With {
    .Key = Key,
    .RedItems = g.Sum(ItemsOfColor(Colors.Red))
})

这清楚地突出显示我们实际上已经内部一个lambda。负责将lambda参数转换为Select到表达式树的编译步骤会看到对ItemsOfColor的调用,并创建一个MethodCallExpression,就像我们期望的那样!

简而言之,将方法调用转换为表达式没有特殊规则,它实际上是一个lambda,而我在EF / LINQ当前版本中的原始问题是不可能的。也许有一天,MS会扩展两个中的一个来识别MethodCallExpression,它会产生一个表达式并进行调用(从而使这种类型的重构成为可能)。