1

VB コンパイラは自動的にラムダをLambdaExpression同等のものに変換します (例: in Dim a As LambdaExpression = Function(x) x.Length)。最近まで、この機能はラムダにのみ適用されると思っていましたが、メソッド呼び出しの結果を引数としてメソッドに渡そうとすると、同じ動作をすることがわかりました。コンパイラは、呼び出しを行うMethodCallExpression代わりに、私の呼び出しを a に変換しました!

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 のコンパイル方法とその副作用をゆっくりと理解するのに役立つシリーズの 3 番目の質問です。パート12

4

1 に答える 1

0

私はついに問題を理解したと思います...だからここに行きます。クエリ式の構文 (上記のように)は、 が通常のメソッド呼び出しであるように見えますが、そうではありません。その「呼び出し」は、実際には、前の行のステートメントのラムダの本体内にあります。ラムダ構文で書き直すと、次のようになります。.RedItems = g.Sum(ItemsOfColor(Colors.Red))Select

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

これは、実際にはすでにラムダの中にいることを明確に強調しています。Selectラムダ引数を式ツリーに変換するコンパイル手順は、期待どおりにへの呼び出しを見て、ItemsOfColorを作成します!MethodCallExpression

要するに、メソッド呼び出しを式に変換するための特別なルールはなく、実際にはラムダであり、現在のバージョンの EF/LINQ では私の元の質問は不可能です。おそらくいつの日か、MS は 2 つのうちの 1 つを拡張しMethodCallExpressionて、式を生成し、呼び出しを行う a を認識します (したがって、このタイプのリファクタリングが可能になります)。

于 2013-04-14T19:55:07.003 に答える