重载,generics类型推断和’params’关键字
我刚注意到一个带有重载决策的奇怪行为。
假设我有以下方法:
public static void DoSomething(IEnumerable items) { // Whatever // For debugging Console.WriteLine("DoSomething(IEnumerable items)"); }
现在,我知道这个方法通常会使用少量显式参数调用,所以为方便起见,我添加了这个重载:
public static void DoSomething(params T[] items) { // Whatever // For debugging Console.WriteLine("DoSomething(params T[] items)"); }
现在我尝试调用这些方法:
var items = new List { "foo", "bar" }; DoSomething(items); DoSomething("foo", "bar");
但在这两种情况下,都会调用params
的重载。 我希望在List
的情况下调用IEnumerable
重载,因为它看起来更匹配(至少对我而言)。
这种行为是否正常? 谁能解释一下呢? 我在MSDN文档中找不到任何关于它的明确信息……这里涉及的重载决策规则是什么?
C#3.0规范的7.4.3节是相关的。 基本上参数数组是扩展的,所以你要比较:
public static void DoSomething(T item)
和
public static void DoSomething(IEnumerable item)
第一个匹配的T
被推断为List
,第二个匹配的T
被推断为string
。
现在考虑参数类型的参数所涉及的转换 – 在第一个中它是List
到List
; 在第二个它的List
到IEnumerable
。 根据7.4.3.4中的规则,第一次转换比第二次转换更好。
反直觉位是类型推断。 如果你把它排除在等式之外,它会像你期望的那样工作:
var items = new List { "foo", "bar" }; DoSomething (items); DoSomething ("foo", "bar");
此时,每次调用中只有一个适用的函数成员。