IEnumerable <T> vs <T>的C#Variance问题

Tho*_*mas 3 c# generics overriding variance

所以,我遇到类似代码的问题如下:

public static String MyFunc<T>(this IEnumerable<T> list) where T : struct
{
    ... some code ...
    return myString;
}

public static String MyFunc<T>(this T o) where T : struct
{
    ... some code ...
    return myString;
}
Run Code Online (Sandbox Code Playgroud)

问题是当尝试在List上调用MyFunc时,它使用第二个函数而不是接受IEnumerable的函数.我知道这与方差有关,但我不确定如何强制它使用第一个函数而不是第二个函数.我用来调用第一个代码的代码是:

List<int> x = new List<int>();
String s = x.MyFunc();
Run Code Online (Sandbox Code Playgroud)

上面的代码立即转到第二个函数,我需要它来使用第一个.我该怎样强迫所需的行为?顺便说一下,我使用的是.NET 4.0

Jon*_*eet 7

它当前选择第二种方法的原因是从类型到自身的转换(第二种方法,T=List<int>转换List<int>List<int>)总是比转换到它实现的类型"更好"(第一种方法,T=int从转换List<int>IEnumerable<int>) .顺便说一句,这与方差无关 - 它只是方法重载算法和类型推断.

请注意,对于当前代码,虽然选择了第二个重载,但随后会发现它无效,因为T违反了T : struct约束.仅选择过载后才检查约束.有关详细信息,请参阅Eric Lippert关于此的博客文章.

我建议你只给两种方法不同的名字.

编辑:正如安东尼在评论中指出,这可以工作,如果你称呼其为:

x.AsEnumerable().MyFunc();
Run Code Online (Sandbox Code Playgroud)

或者只是将声明更改为:

IEnumerable<int> x = new List<int>();
x.MyFunc();
Run Code Online (Sandbox Code Playgroud)

我并不完全清楚为什么它在这里更好 - 在这种情况下,在类型参数替换之后,你IEnumerable<T>在两种情况下基本上都得到了参数类型.但是,我仍然强烈建议在这里使用不同的名称.事实上,让我对规范感到困惑,以确定调用哪个重载应该足以表明每个阅读代码的人都不会立即清楚这种行为.

编辑:我认为原因在于(来自C#5规范,第7.5.3.2节):

  • 类型参数不是非类型参数的特定参数

因此,即使后者涉及类型参数,也不如T特定.我仍然不清楚这是否是语言设计者的预期行为...我可以看到为什么涉及类型参数的类型应该被视为不比不涉及类型参数的类型更具体,但不是这个措辞...IEnumerable<T>