1

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

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.RedLambdaExpressionItemsOfColor

问题:为什么编译器认为这是我想要的行为,有没有办法关闭它?

注意:这是系列中的第三个问题,它慢慢地帮助我了解 LINQ 是如何编译的及其副作用。第一部分和第二部分。

4

1 回答 1

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并创建 a MethodCallExpression,正如我们所期望的那样!

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

于 2013-04-14T19:55:07.003 回答