重载,泛型类型推断和'params'关键字

时间:2009-11-30 15:39:48

标签: c# generics type-inference params-keyword overload-resolution

我刚注意到一个带有重载决策的奇怪行为。

假设我有以下方法:

public static void DoSomething<T>(IEnumerable<T> items)
{
    // Whatever

    // For debugging
    Console.WriteLine("DoSomething<T>(IEnumerable<T> items)");
}

现在,我知道这个方法通常会使用少量显式参数调用,所以为方便起见,我添加了这个重载:

public static void DoSomething<T>(params T[] items)
{
    // Whatever

    // For debugging
    Console.WriteLine("DoSomething<T>(params T[] items)");
}

现在我尝试调用这些方法:

var items = new List<string> { "foo", "bar" };
DoSomething(items);
DoSomething("foo", "bar");

但在这两种情况下,调用params的重载。我希望在IEnumerable<T>的情况下调用List<T>重载,因为它看起来更合适(至少对我而言)。

这种行为是正常的吗?谁能解释一下呢?我在MSDN文档中找不到任何关于它的明确信息......这里涉及的重载决策规则是什么?

1 个答案:

答案 0 :(得分:9)

C#3.0规范的7.4.3节是相关的位。基本上参数数组是扩展的,所以你要比较:

public static void DoSomething<T>(T item)

public static void DoSomething<T>(IEnumerable<T> item)

第一场比赛的T推断为List<string>,第二场比赛的T推断为string

现在考虑参数类型的参数所涉及的转换 - 在第一个参数类型List<string>List<string>;在第二个List<string>IEnumerable<string>。根据7.4.3.4中的规则,第一次转换比第二次转换更好。

反直觉位是类型推断。如果你把它排除在等式之外,它将按照你的预期运作:

var items = new List<string> { "foo", "bar" };
DoSomething<string>(items);
DoSomething<string>("foo", "bar");

此时,每次通话中只有一个适用的功能成员。