2011-11-26 10 views
22

私はクラスがあるとします。Funcと式の間にラムダ式の引数があいまいになるのはなぜですか?<Func>?

class MyClass { 
    public int MyMethod(Func<int, int> f) { return 0; } 
    public int MyMethod(Expression<Func<int, int>> f) { return 1; } 
} 

私はラムダ式でメソッドを呼び出すしようとすると、私はコールは2つのオーバーロードの間であいまいであることを示すコンパイルエラーを取得:

var myClass = new MyClass(); 
myClass.MyMethod(x => 1 + x); // Error! 

正常に動作し、もちろん、明示的なタイプで呼び出すことながら:

myClass.MyMethod((Func<int, int>)(x => 1 + x)); // OK, returns 0 
myClass.MyMethod((Expression<Func<int, int>>)(x => 1 + x)); // OK, returns 1 

式ツリーは、より多くの情報(実際のコード)を含み、そして私がwaかもしれませんこの情報を利用できるようにするには、この情報を利用してください。しかし、私もコードを代理人と一緒に使いたいと思っています。残念なことに、このあいまいさにより、2つの呼び出しを区別する別の方法を見つける必要があります。これは、きれいなAPIを混乱させます。

C#仕様では、この特定の状況について何も言及していないため、この動作は仕様と一致します。

ただし、表現ツリーはデリゲートよりも優先されるべきであるという議論があります。 Compileメソッドは、式ツリーからデリゲートへの明示的な変換として機能します。式ツリーには詳細情報が含まれています。デリゲートにコンパイルすると、その情報が失われます。他の方向への変換はありません。

表現木を好まない理由はありますか?

+3

「Func」を支持する議論は、比較的高価な合併段階を経ることなく直接実行できるということです。 – Lee

答えて

6

タイトルの質問に答えると、タイプシステムに「ラムダ式」の概念がないため、曖昧です。これはデリゲートまたは式ツリーに変換できるコンパイラ機能ですので、変換する型を明示する必要があります。ほとんどの場合、ターゲットはラムダ式が使用されているコンテキストのためコンパイラによって自動的に推論されます。例えば、IEnumerable拡張方法のラムダの使用と、拡張方法のIQueryableのラムダの使用。

ここで、なぜ表現ツリーが常に好都合であるのかという質問に答えるために、あなたはMagnatLUがすでに述べたパフォーマンス引数を持っています。Expressionを受け取り、それを実行できるようにCompileを呼び出すと、デリゲートを受け入れる場合と比べて常に遅くなります。

2つの意味に違いがありますが、デリゲートはコードを実行する方法で、式ツリーは実際のコードの説明です。

私があなただったら、表現を受け入れるメソッドの名前を、デリゲートベースのものに追加するものを明確に反映するものに変更することを選択します。

+1

ラムダ式が2つの方法で解釈できるという事実は、それ自体が1つを優先するというルールがないことを意味しません。だから私はあなたの答えのその部分が本当に好きではありません。しかし、残りは素晴らしいです。ありがとう! –

0

式ツリーの構築とコンパイルには時間がかかり、GCに大きな負荷をかける可能性があります。実際に実行する必要がない限り、実行時に式を構築してコンパイルするべきではありません。

編集:また、すべての式や方法がExpression<E>であるとは限りません。 Func<U, V>は、パラメータと戻り値の型のみを扱い、そのような制限はありません。

2

コンパイラは式ツリーまたはデリゲートを選択するかどうかをどのように知っていますか?それはあなたの決定であり、コンパイラの決定ではありません。

すべてのlinqメソッドは、デリゲートと式の両方を提供しますが、ターゲットタイプの形式で拡張されています。

Enumerable.Where<T>(this IEnumerable<T> en , Func<T,bool> filter) 
Queryable.Where<T>(this IQueryable<T> en , Expression<Func<T,bool>> filter) 

したがって、ターゲットタイプのコンパイラに基づいて選択できます。コンパイラはプログラムであり、実際にはマシンであり、コンテキストフリーであり、人間のようにより良くなると判断することはできません。ルールに従うだけで、それらのルールは明白である必要があります。

+1

コンパイラがそれをあいまいであるとラベル付けするのは、なぜなら、それが省略された仕様であるからです。問題は、なぜ言語設計者があいまいにしたのかということです。 –

+0

すべての置換と組み合わせが設計できないため、具体的な答えが得られないのはなぜですか?この方法では、優先度が低く、まれな使用シナリオのルールが多数あります。すべてのデザインルールを推測して追加するのは現実的ではありません。 –

関連する問題