关于泛型和IEnumerable的方法重载决策

the*_*onk 19 .net c# overloading overload-resolution

前几天我注意到这一点,说你有两个重载方法:

public void Print<T>(IEnumerable<T> items) {
    Console.WriteLine("IEnumerable T"); 
}
public void Print<T>(T item) {
    Console.WriteLine("Single T"); 
}
Run Code Online (Sandbox Code Playgroud)

这段代码:

public void TestMethod() {  
    var persons = new[] { 
        new Person { Name = "Yan", Age = 28 },
        new Person { Name = "Yinan", Age = 28 } 
    };  
    Print(persons);
    Print(persons.ToList()); 
}
Run Code Online (Sandbox Code Playgroud)

打印:

Single T
Single T
Run Code Online (Sandbox Code Playgroud)

在这些情况下,为什么Person[]和他们相比List<Person>更好?TIEnumerable<T>

谢谢,

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

public void Print<T>(List<T> items) {
    Console.WriteLine("List T");
}
Run Code Online (Sandbox Code Playgroud)

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

TTo*_*oni 18

问题的第一部分(没有特定于列表的重载)很容易.让我们考虑一下Array调用,因为它对两个调用都是一样的:

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

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

添加过载后,List调用会产生第三个可能的重载:Print<Person>(List<Person> items).该论点与第一Print<List<Person>>(List<Person> items)部分相同,但第7.4.3.2节提供了该语言的解决方案

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

所以Print<Person>重载比重载更具体Print<List<Person>>,List版本胜过IEnumerable,因为它不需要隐式转换.