2

C# コンパイラで何が起こって、次のあいまいな呼び出しコンパイル エラーが発生しますか?

同じ問題が拡張メソッドにも当てはまります。または、TestClassがジェネリックであり、静的メソッドではなくインスタンスを使用している場合にも当てはまります。

解決するのはかなり簡単だと思いますが(メソッド呼び出しでキャストsecondInstanceするTest1など)、メソッド選択のためにコンパイラによってどのロジックが適用されているのかもっと知りたいです。

私の仮定は、コンパイラがメソッド検出に特定レベルの特定尺度 (CSS など) を適用して、最も具体的な一致を判断することです。これは無効ですか?

class Type1 { }
class Type2 : Type1 {}

class TestClass
{
    public static void Do<T>(T something, object o) where T : Type1
    {} 

    public static void Do(Type1 something, string o)
    {}
}

void Main()
{
    var firstInstance = new Type1();
    TestClass.Do(firstInstance, new object()); // Calls Do<T>(T, obj)
    TestClass.Do(firstInstance, "Test"); // Calls Do(Type1, string)

    var secondInstance = new Type2();
    TestClass.Do(secondInstance, new object()); // Calls Do<T>(T, obj)
    TestClass.Do(secondInstance, "Test"); // "The call is ambiguous" compile error
}

// 編集: mike z は、「キャスト距離」がメソッド選択の重みとして使用されていると私が解釈した概念を提案しました。これのテストはそれをサポートしているようです (ただし、Type->Generic Type がどのように重み付けされているかはわかりません)。

// Add the following two methods to TestClass
public static void Do<T>(T something) where T : Type1
{} 

public static void Do(Type1 something)
{}

public static void Do<T>(T something, object o) where T : Type1
{} 

public static void Do(Type1 something, string o)
{}

void Main()
{
    var firstInstance = new Type1();

    // Can't select string
    TestClass.Do(firstInstance, new object()); // Calls Do<T>(T, obj)

    // Do() distance is 0, Do<T> distance is 1
    TestClass.Do(firstInstance, "Test"); // Calls Do(Type1, string)

    // Do() distance is 0, Do<T> distance is ? (but more than 0?)
    TestClass.Do(firstInstance); // Calls Do(Type1)

    var secondInstance = new Type2();

    // Can't select string
    TestClass.Do(secondInstance, new object()); // Calls Do<T>(T, obj)

    // Do() distance is 1, Do<T> distance is 1
    TestClass.Do(secondInstance, "Test"); // "The call is ambiguous" compile error

    // Do() distance is 1, Do<T> distance is ? (but less than 1?)
    TestClass.Do(secondInstance); // Calls Do<T>(T)

}
4

1 に答える 1

5

過負荷の解決については、セクション 7.5.3 で説明されています。複雑ですが、基本的な考え方は、必要な変換の数と種類に基づいてコンパイラが「最適な」オーバーロードを決定するというものです。

ケース 1 の場合、ジェネリック オーバーロードで正確な型の一致があります。
ケース 2 の場合、非ジェネリック オーバーロードで型が完全に一致します。
ケース 3 の場合、ジェネリック オーバーロードは完全一致です。注:あなたのコメントは間違っています。の型にTなりますType2
ケース 4 の場合、ジェネリック オーバーロードでは string から object への変換が必要ですが、非ジェネリック メソッドでは からType2への変換が必要Type1です。これらはどちらも基本型への参照変換であることに注意してください。どちらの場合も同じ種類の変換が必要なため、コンパイラは決定を拒否し、呼び出しがあいまいであるというエラーを返します。「ベスト」マッチはありません。

于 2013-10-25T03:57:01.640 に答える