【问题标题】:C# Variance Issue with IEnumerable<T> vs <T> [duplicate]IEnumerable<T> 与 <T> 的 C# 差异问题 [重复]
【发布时间】:2014-06-05 17:45:04
【问题描述】:

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

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

【问题讨论】:

  • 在这种情况下,由于where T : struct 在第二种情况下,它实际上不会编译;该重载将被选择,但随后被发现是无效的。

标签: c# generics overriding variance


【解决方案1】:

它目前选择第二种方法的原因是从一个类型到自身的转换(第二种方法,T=List&lt;int&gt;,从List&lt;int&gt;List&lt;int&gt; 的转换)总是比转换到类型它实现(第一种方法,T=int,从List&lt;int&gt;IEnumerable&lt;int&gt; 的转换)。顺便说一句,这与方差无关 - 它只是方法重载算法和类型推断。

请注意,使用您当前的代码,尽管选择了第二个重载,但随后会发现它是无效的,因为 T 违反了 T : struct 约束。仅在选择重载之后检查约束。详情请见Eric Lippert's blog post on this

我建议你给这两种方法起不同的名字。

编辑:正如 Anthony 在 cmets 中所指出的,如果您将其称为:

x.AsEnumerable().MyFunc();

或者只是将声明更改为:

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

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

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

  • 类型参数不如非类型参数具体

所以T 没有IEnumerable&lt;T&gt; 特定,尽管后者涉及一个类型参数。我仍然不清楚这是否是语言设计者的预期行为......我可以理解为什么涉及类型参数的类型应该被视为比不涉及类型的类型更不具体参数,但不完全是这个措辞......

【讨论】:

  • 我只是希望有一种方法可以强制它优先于另一个。
  • @user976921:为什么只给这两种方法不同的名称?这样一来,任何阅读代码的人都可以清楚地看到其中涉及的方法。
  • @user976921,将变量键入为IEnumerable&lt;T&gt;,进行转换,调用AsEnumerable(),等等,但在这一点上,这对您来说更多(基本上没有记录)样板,它会更简单只需按照 Jon 的建议使用不同名称的方法即可。
  • @AnthonyPegram:使用AsEnumerable 无济于事 - 它仍然会调用第二个重载,只需使用T=IEnumerable&lt;int&gt;
  • 我想保持名称相同的原因是为了保持一致性,因为这两个函数本质上会做同样的事情,唯一的区别是一个处理倍数(IEnumerable),其中另一个只处理一个()。此外, .AsEnumerable 确实选择了正确的方法,但正如你所说,它会产生它自己的问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多