2011-02-05 177 views
18

我注意到這個有一天,說你有兩個重載的方法:方法重載

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>更好地匹配到T比他們在這些情況下IEnumerable<T>

感謝,

UPDATE: 另外,如果您有其他重載

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

Print(persons.ToList());將實際打印List T而不是Single T

+2

調用`打印(人員爲IEnumerable );`應調用另一種方法。泛型方法查找不會執行從`Person []`到`IEnumerable `的隱式轉換。當你調用`person.ToList()`時,你的直接類型是`List `(也不需要隱式轉換)。 – 2011-02-05 23:24:53

+0

+1我一直在擺弄這個問題。 – Dan 2013-07-10 19:10:17

回答

17

問題的第一部分(沒有列表特定的過載)很容易。讓我們考慮一下Array調用,因爲它對兩個調用都是一樣的:

首先,類型推斷產生兩種可能的調用實現:Print<Person[]>(Person[] items)Print<Person>(IEnumerable<Person> items)

然後重載決議開始,第一個贏,因爲第二個需要隱式轉換,其中第一個沒有(見C#規範§7.4.2.3)。同樣的機制適用於List變體。

由於增加了過載,因此使用List調用會產生第三種可能的過載:Print<Person>(List<Person> items)。的參數是相同的與Print<List<Person>>(List<Person> items)但同樣,節7.4.3.2提供了與語言

遞歸分辨率,構造類型比另一種構造類型更具體的(具有相同數目的類型的參數)如果至少有一個類型參數更具體,沒有類型參數比另一個類型參數不那麼具體。

所以Print<Person>過載比Print<List<Person>>超載更加具體和列表版本戰勝了IEnumerable,因爲它不需要隱式轉換。

3

因爲從仿製藥Print(Person[] item)Print(List<Person> item)生成的方法比IEnumerable<T>更好匹配。

編譯器生成基於你的類型參數的方法,所以通用模板Print<T>(T item)會被編譯爲Print(Person[] item)Print(List<Person> item)(當然,無論何種類型代表List<Person>在編譯)。因此,方法調用將被編譯器解析爲接受直接類型的特定方法,而不是執行Print(IEnumerable<Peson>)

+0

換句話說,打印將永遠被視爲最好的匹配,因爲T可以是任何東西?但是,如果您添加打印(列表項目)方法,這將是打印(persons.ToList) – theburningmonk 2011-02-05 22:19:12