关于generics和IEnumerable的方法重载解析
前几天我注意到了这一点,说你有两个重载方法:
public void Print(IEnumerable items) { Console.WriteLine("IEnumerable T"); } public void Print(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
IEnumerable
在这些情况下与IEnumerable
T
匹配得更好?
谢谢,
更新:此外,如果你有另一个重载
public void Print(List items) { Console.WriteLine("List T"); }
Print(persons.ToList());
实际上会打印List T
而不是Single T
问题的第一部分(没有特定于列表的重载)很容易。 让我们考虑一下Array调用,因为它对两个调用都是一样的:
首先,类型推断产生两种可能的调用通用实现: Print
和Print
。
然后重载决策启动并且第一个获胜,因为第二个需要隐式转换,而第一个不需要(参见C#规范的第7.4.2.3节)。 相同的机制适用于List变体。
添加过载后,List调用会生成第三个可能的重载: Print
。 该参数与Print
但同样,第7.4.3.2节提供了该语言的分辨率 >(List
递归地,如果至少一个类型参数更具体,并且没有类型参数比另一个中的相应类型参数更不具体,则构造类型比另一个构造类型(具有相同数量的类型参数)更具体。
因此Print
重载比Print
重载更具体,并且List版本胜过IEnumerable,因为它不需要隐式转换。 >
因为从genericsPrint(Person[] item)
和Print(List
生成的方法比IEnumerable
更好。
编译器根据您的类型参数生成这些方法,因此通用模板Print
将被编译为Print(Person[] item)
和Print(List
(嗯,无论何种类型代表编译时List
。 因此,方法调用将由编译器解析为接受直接类型的特定方法,而不是Print(IEnumerable
。