vb.netlinq

Can I control what the .NET compiler automatically converts to expressions


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.


Solution

  • 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).