The VB compiler automatically converts lambda's to their LambdaExpression
equivalents (eg in Dim a As LambdaExpression = Function(x) x.Length
). Until recently, I thought that feature only applied to lambdas, but then I found the same behavior on trying to pass the result of a method call as an argument to a method. The compiler converted my call to a MethodCallExpression
instead of making the call!
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
contains a MethodCallExpression
to call ItemsOfColor
with Colors.Red
as an argument instead of a LambdaExpression
with the result of the ItemsOfColor
call as I would have expected.
THe question(s): Why does the compiler assume this is the behavior I want, and, is there any way to turn it off?
NOTE: This is the third question in a series which has slowly been helping me understand how LINQ is compiled and the side effects thereof. Part one and two.
I think I finally understand the problem... so here goes. The query expression syntax (as above) makes it appear that .RedItems = g.Sum(ItemsOfColor(Colors.Red))
is a normal method call, but it's not. That "call" is actually inside the body of a lambda for the Select
statement on the previous line. Rewritten in lambda syntax, this would be:
.Select(Function(x) New With {
.Key = Key,
.RedItems = g.Sum(ItemsOfColor(Colors.Red))
})
Which highlights clearly that we're actually inside a lambda already. The compilation step responsible for converting the lambda argument to Select
to an expression tree sees the call to ItemsOfColor
and creates a MethodCallExpression
, exactly as we would expect!
In short, there is no special rule to convert a method call to an expression, it's actually a lambda, and my original questions are impossible in the current version of EF / LINQ. Maybe one day MS will extend one of the two to recognize a MethodCallExpression
which would produce an expression and make the call (thus making this type of refactoring a possibility).