19

式をいじっていて、いくつかの点で混乱しました

  1. 同じ LamdaExpression を Expression および/または Func の両方に割り当てることができます。ただし、Func を Expression に (または Expression を Func に) 割り当てることはできません。なぜそれができないのでしょうか。Expression と Func の間の変換演算子が定義されているかどうかを探しましたが、何も見つかりませんでした。

    Func<int, int> sumFunc            = i => i + i;
    Expression<Func<int, int>> sumExp = i => i + i;
    
    // sumExp = sumFunc; // Cannot convert source type 'System.Func<int,int>' to target type 'System.Linq.Expressions.Expression<System.Func<int,int>>'
    // sumFunc = sumExp; // Cannot convert source type 'System.Linq.Expressions.Expression<System.Func<int,int>>' to target type 'System.Func<int,int>'
    
  2. LambdaExpression をオブジェクトに割り当てることさえできません。繰り返しますが、なぜそれができないのでしょうか。

    // object o = i => i + i; // Cannot convert source type 'lambda expression' to target type 'object'
    
  3. コンパイラには何かがあると思います。もしそうなら、この (紛らわしい) 方法で動作し、何かを利用するカスタム型を作成できますか?

4

3 に答える 3

33

C# 言語仕様に関しては、次のようなラムダ式

i => i + i

無名関数です。この分類の式は、互換性のあるデリゲート型または式ツリー型に暗黙的に変換できます。これが、両方を書くことができる理由です

Func<int, int> sumFunc            = i => i + i;
Expression<Func<int, int>> sumExp = i => i + i;

1 つ目はデリゲート型、2 つ目は式ツリー型です。これらの型の間で暗黙的な変換が行われないため、割り当てsumFunc = sumExpたり、その逆を行ったりすることはできません。ただし、式ツリーsumExpはラムダ式を表しているため、その式を実行可能なデリゲートにコンパイルして に割り当てることができますsumFunc。これは互換性のあるデリゲートであるためです。

sumFunc = sumExp.Compile();

デリゲートは式ツリーに簡単に「逆コンパイル」できないため、他の方向は不可能です。

書けない理由

object o = i => i + i;

つまり、匿名関数自体は値や型を持たず、デリゲートまたは式ツリー型に変換できるだけです。どちらが必要かをコンパイラに伝える必要があるため、最初に変換してから、結果を type の変数に割り当てることができますobject

object sumFuncObject = (Func<int, int>) (i => i + i);
object sumExpObject = (Expression<Func<int, int>>) (i => i + i);

最後の質問について: この「魔法」を割り当てに適用できるように、複雑な型の間でカスタムの暗黙的または明示的な変換を作成できます。詳細については、「変換操作プログラミング ガイド」を参照してください。

于 2013-01-05T23:05:52.453 に答える
0

表現は抽象化です。これにより、Linq はデータベース、XML、または別のデータ ソースの SQL クエリを効率的に構築できます。概念は抽象構文ツリーに似ており、クエリの構文要素を格納して、Linq プロバイダーがクエリを作成できるようにします。

期待どおりに機能する場合は、ラムダ関数の抽象構文ツリーを取得して、式オブジェクトのツリーを生成する必要があります。まあ、私の知る限り、それは実際には不可能です。

于 2013-01-05T19:34:02.133 に答える