【问题标题】:Why doesn't .Net 4 allow me to pass in an array of an interface? [duplicate]为什么.Net 4 不允许我传入接口数组? [复制]
【发布时间】:2013-03-22 02:41:45
【问题描述】:

我有一个 Circle 对象数组(其中 Circle 实现了 IShape 接口,并且我有一个参数为 List<IShape> 的函数......为什么我不能将我的 Circles 数组传递给它?

Visual Studio 给我一个构建错误,说无法将 List<Circle> 转换为 List<IShape>

【问题讨论】:

  • 你的意思是你有一个List<Circle>和一个函数Foo(List<IShape> c)Circle : IShape?考虑Foo 是否有以下行:c.Add(new Square())
  • 这是一个经常被问到的问题。搜索涉及可枚举类型协方差的问题。
  • IEnumerable 就足够了吗?并非所有类型都是协变的。
  • 因为不能直接将List<Circle>转换成List<IShape>,但是应该可以传入myCircles.OfType<IShape>().ToList()

标签: c# collections covariance


【解决方案1】:

简短的回答是因为函数Foo可以这样实现:

void Foo(IList<IShape> c)
{
    c.Add(new Square());
}

如果您将List&lt;Circle&gt; 传递给Foo,则提供的类型将无法存储Square,即使类型签名声称它是可以的。 IList&lt;T&gt; 不是covariant:一般的IList&lt;Circle&gt; 不能是IList&lt;IShape&gt;,因为它不能支持任意形状的添加。

解决方法是使用IEnumerable&lt;IShape&gt; 接受Foo 中的参数,但这并不适用于所有情况。 IEnumerable&lt;T&gt; 是协变的:专门的 IEnumerable&lt;Circle&gt; 符合一般 IEnumerable&lt;IShape&gt; 的合同。


这种行为也是一件好事。一个不应该是协变的东西的经典例子是数组。以下代码将编译,但在运行时会失败:

void Bar()
{
    // legal in C#:
    object[] o = new string[10];
    // fails with ArrayTypeMismatchException: can't store Int in a String[]
    o[0] = 10;
}

【讨论】:

  • 实际上,IEnumerable&lt;Circle&gt; 不会被带有参数IEnumerable&lt;IShape&gt; 的方法接受,如果方法签名是@,则必须将传递给函数的集合转换为IEnumerable&lt;IShape&gt; 的实例987654339@.
  • @FrancisR.Griffiths-Keam,你错了。从 .NET 4 开始,IEnumerable 在 T 上是协变的,这意味着只要 X 派生自(或实现)T,就可以替换 IEnumerable
  • @AnthonyPegram 啊,我错过了那个备忘录,谢谢你把记录说清楚。
  • 同样重要的是要注意IList&lt;T&gt; 没有这个相同的属性(并且不能)。
猜你喜欢
  • 2011-08-18
  • 1970-01-01
  • 1970-01-01
  • 2012-01-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-26
相关资源
最近更新 更多