19

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

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>更好地匹配?TIEnumerable<T>

谢谢,

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

public void Print<T>(List<T> items) {
    Console.WriteLine("List T");
}

Print(persons.ToList());实际上会打印List T而不是Single T.

4

2 回答 2

18

您问题的第一部分(没有特定于 List 的重载)很容易。让我们考虑 Array 调用,因为它对两个调用的工作方式相同:

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

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

通过添加重载,使用 List 调用生成第三种可能的重载:Print<Person>(List<Person> items). 参数与 the 相同,Print<List<Person>>(List<Person> items)但同样,第 7.4.3.2 节提供了该语言的解决方案

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

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

于 2011-02-05T23:14:36.830 回答
3

因为从泛型生成的Print(Person[] item)方法Print(List<Person> item)IEnumerable<T>.

编译器会根据您的类型参数生成这些方法,因此通用模板Print<T>(T item)将被编译为Print(Person[] item)and Print(List<Person> item)(好吧,List<Person>在编译时代表 a 的任何类型)。因此,编译器会将方法调用解析为接受直接类型的特定方法,而不是Print(IEnumerable<Peson>).

于 2011-02-05T22:13:12.393 回答