IEnumerable <t> vs <t> </t> </t>的C#方差问题

时间:2014-06-05 17:45:04

标签: c# generics override 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;
}

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

List<int> x = new List<int>();
String s = x.MyFunc();

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

1 个答案:

答案 0 :(得分:7)

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

请注意,对于您当前的代码,虽然选择了第二个重载,然后会发现它无效,因为T违反了T : struct约束。仅在选择过载后才检查约束。有关详细信息,请参阅Eric Lippert's blog post on this

我建议你给这两种方法命名不同。

编辑:正如安东尼在评论中指出的那样,如果您将其称为

可以
x.AsEnumerable().MyFunc();

或者只是将声明更改为:

IEnumerable<int> x = new List<int>();
x.MyFunc();

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

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

  
      
  • 类型参数的特定性低于非类型参数
  •   

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