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");
}