0

通常、C#コンパイラは、メソッドのバインドと型引数の推論について賢明です。しかし、私はそれを困惑させたようです。

class Obj
{
    void Handler( int a, int b ) { }

    Obj() { Method( "", Handler ); }

    public void Method<T>( T t, Action<T> action ) { }

    public void Method<T, U>( T t, Action<U, U> action ) { }
}

このMethod呼び出しにより、コンパイラエラーが発生します。

引数2:「メソッドグループ」から「System.Action」に変換できません。

コンパイラが呼び出しが2番目のオーバーロードに適合することに気付かないのはなぜですか?Method<string, int>( "", Handler )またはのように呼び出しをより明示的にすることでコンパイルできますMethod( "", (Action<int, int>)Handler )。しかし、なぜこれが必要なのですか?

4

1 に答える 1

6

Anthony の提案を取り入れて、次のことを考えてみましょう。

class Obj
{
    void Handler( int a, int b ) { }
    Obj() { Method( "", Handler ); }
    public void Method<T, U>( T t, Action<U, U> action ) { }
}

過負荷の解決に失敗します。なんで?さて、T と U を推測する必要があります。明らかに T は文字列です。ウとは?

このビットは重要です。 Handler が何であるかがわかった後、 U が何であるかを推測します。さて、Handler が何であるかを知っていると言うかもしれません。しかし、C# には、メソッド グループにメソッドが 1 つしかない場合、オーバーロード解決ゲームに自動的に勝つというルールはありません。ルールは、Handlerに関連付けられたメソッド グループでオーバーロード解決を実行することによって、Handler の意味が決定されるというものです。オーバーロードの解決では引数が考慮れますが、Handler の引数はありません。これは、可能な唯一の引数リストが (U, U) であり、最初に決定しようとしているのが U であるためです。

したがって、オーバーロードの解決はここで失敗します。さて、もし私たちが持っていたとしたら:

class Obj
{
    double M(string s) { }
    Obj() { Method( "", M ); }
    public void Method<T, U>(T t, Func<T, U> f) { }
}

それはうまくいきます。T が文字列であると推測し、M のオーバーロード解決を行い、M が を意味すると判断しdouble M(string s)、U が double であることがわかりました。

于 2013-03-21T04:34:38.783 に答える