关于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(Person[] items)Print(IEnumerable items)

然后重载决策启动并且第一个获胜,因为第二个需要隐式转换,而第一个不需要(参见C#规范的第7.4.2.3节)。 相同的机制适用于List变体。

添加过载后,List调用会生成第三个可能的重载: Print(List items) 。 该参数与Print>(List items)但同样,第7.4.3.2节提供了该语言的分辨率

递归地,如果至少一个类型参数更具体,并且没有类型参数比另一个中的相应类型参数更不具体,则构造类型比另一个构造类型(具有相同数量的类型参数)更具体。

因此Print重载比Print>重载更具体,并且List版本胜过IEnumerable,因为它不需要隐式转换。

因为从genericsPrint(Person[] item)Print(List item)生成的方法比IEnumerable更好。

编译器根据您的类型参数生成这些方法,因此通用模板Print(T item)将被编译为Print(Person[] item)Print(List item) (嗯,无论何种类型代表编译时List 。 因此,方法调用将由编译器解析为接受直接类型的特定方法,而不是Print(IEnumerable)