2011-02-05 126 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