19

先日これに気づきました。たとえば、2 つのオーバーロードされたメソッドがあるとします。

public void Print<T>(IEnumerable<T> items) {
    Console.WriteLine("IEnumerable T"); 
}
public void Print<T>(T item) {
    Console.WriteLine("Single T"); 
}

このコード:

public void TestMethod() {  
    var persons = new[] { 
        new Person { Name = "Yan", Age = 28 },
        new Person { Name = "Yinan", Age = 28 } 
    };  
    Print(persons);
    Print(persons.ToList()); 
}

プリント:

Single T
Single T

これらの場合、なぜ彼らはよりもPerson[]よくList<Person>一致しているのですか?TIEnumerable<T>

ありがとう、

更新: また、別の過負荷がある場合

public void Print<T>(List<T> items) {
    Console.WriteLine("List T");
}

Print(persons.ToList());List Tの代わりに実際に印刷されSingle Tます。

4

2 に答える 2

18

質問の最初の部分 (リスト固有のオーバーロードなし) は簡単です。両方の呼び出しで同じように機能するため、Array 呼び出しを考えてみましょう。

まず、型推論は呼び出しの 2 つの可能なジェネリック実装を生成します:Print<Person[]>(Person[] items)Print<Person>(IEnumerable<Person> items).

次に、オーバーロードの解決が開始され、最初の変換が優先されます。これは、2 番目の変換では暗黙の変換が必要ですが、最初の変換では必要ないためです (C# 仕様の §7.4.2.3 を参照)。List バリアントでも同じメカニズムが機能します。

追加されたオーバーロードにより、List 呼び出しで 3 番目の可能なオーバーロードが生成されますPrint<Person>(List<Person> items)。引数は と同じですがPrint<List<Person>>(List<Person> items)、セクション 7.4.3.2 で言語の解決策が提供されます。

再帰的に、少なくとも 1 つの型引数がより具体的であり、他の型引数の対応する型引数よりも具体的でない型引数がない場合、構築された型は (同じ数の型引数を持つ) 別の構築された型よりも具体的です。

したがって、Print<Person>オーバーロードはオーバーロードよりも具体的でPrint<List<Person>>あり、List バージョンは暗黙的な変換を必要としないため、IEnumerable よりも優先されます。

于 2011-02-05T23:14:36.830 に答える
3

ジェネリックスから生成されたメソッドPrint(Person[] item)Print(List<Person> item)、よりも一致するためIEnumerable<T>です。

コンパイラは型引数に基づいてこれらのメソッドを生成しているため、ジェネリックテンプレートはandPrint<T>(T item)としてコンパイルされます(まあ、どの型もコンパイル時にを表します)。そのため、メソッド呼び出しは、の実装ではなく、直接型を受け入れる特定のメソッドとしてコンパイラーによって解決されます。Print(Person[] item)Print(List<Person> item)List<Person>Print(IEnumerable<Peson>)

于 2011-02-05T22:13:12.393 に答える