C# 关于泛型和IEnumerable的方法重载解析

C# 关于泛型和IEnumerable的方法重载解析,c#,.net,overloading,overload-resolution,C#,.net,Overloading,Overload Resolution,前几天我注意到了这一点,假设您有两个重载方法: public void Print<T>(IEnumerable<T> items) { Console.WriteLine("IEnumerable T"); } public void Print<T>(T item) { Console.WriteLine("Single T"); } 印刷品: Single T Single T 为什么在这些情况下,Person[]和List与T的

前几天我注意到了这一点,假设您有两个重载方法:

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

Single T
Single T
为什么在这些情况下,
Person[]
List
T
的匹配比与
IEnumerable
的匹配更好

谢谢

更新: 另外,如果你有另一个过载

public void Print<T>(List<T> items) {
    Console.WriteLine("List T");
}
公共作废打印(列表项){
控制台写入线(“列表T”);
}

Print(persons.ToList())
实际上将打印
列表T
而不是
单个T

,因为从泛型
打印(Person[/item)
打印(列表项)
生成的方法比
IEnumerable
更匹配


编译器正在根据您的类型参数生成这些方法,因此泛型模板
Print(T项)
将被编译为
Print(Person[]item)
Print(List项)
(无论何种类型在编译时表示
List
)。因此,方法调用将由编译器解析为接受直接类型的特定方法,而不是
Print(IEnumerable)
的实现问题的第一部分(没有列表特定的重载)很简单。让我们考虑数组调用,因为它对于两个调用都是相同的:

首先,类型推断生成调用的两种可能的通用实现:
Print(Person[]items)
Print(IEnumerable items)

然后,重载解析开始生效,第一个解决方案获胜,因为第二个解决方案需要隐式转换,而第一个解决方案则不需要(见《C#规范》第7.4.2.3节)。同样的机制也适用于列表变量

添加重载后,第三种可能的重载将通过列表调用生成:
Print(List items)
。参数与
打印(列表项)
相同,但第7.4.3.2节再次提供了语言解决方案

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


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

换句话说,Print将始终被视为最佳匹配,因为T可以是任何东西?但是如果你添加一个Print(List items)方法,那就是Print(persons.ToList)调用的方法,根据Eric Lippert的这篇博文,这不是C#泛型的工作方式,你在C++中描述的模板调用
Print(persons as IEnumerable)
应该调用另一个方法。泛型方法查找不会执行从
Person[]
IEnumerable
的隐式转换。当你调用
person.ToList()
时,你的直接类型是一个
列表(也不需要隐式转换)。+1我已经处理了这个问题一段时间了。谢谢你提到隐式转换,现在一切都有意义了
public void Print<T>(List<T> items) {
    Console.WriteLine("List T");
}