2013-03-22 48 views
0

我有圆的物体(如圈实现IShape接口的数组和我有了的List<IShape>参数的函数。为什么我不能在我的圈子到此的数组传递?为什么.Net 4不允许我传入一个接口数组?

视觉工作室给我生成错误的说法不能转换List<Circle>List<IShape>

+2

你的意思是你有一个列表''和功能'美孚(名单 C)'和'圈:IShape'?考虑'Foo'是否有'c.Add(new Square())'这一行。 – 2013-03-22 02:44:25

+2

这是一个经常被问到的问题。搜索包含可枚举类型的协方差的问题。 – 2013-03-22 02:44:49

+1

请问IEnumerable 够用吗?并非所有类型都是协变的。 – 2013-03-22 02:45:21

回答

5

简短的回答是,因为功能Foo可以实现这样的:

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

如果你通过了List<Circle>Foo,所提供的类型将不能存储Square,即使类型签名声称它没问题。 IList<T>不是covariant:一般IList<Circle>不能是IList<IShape>,因为它不支持添加任意形状。

修复方法是使用IEnumerable<IShape>来接受Foo中的参数,但这在所有情况下都不起作用。 IEnumerable<T>是协变:专门的IEnumerable<Circle>符合一般IEnumerable<IShape>的合同。


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

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

实际上,'IEnumerable '不会被具有参数'IEnumerable '的方法接受'',您必须将您传递给该函数的集合转换为如果方法签名是'Foo(IEnumerable 形状)''IEnumerable '的实例。 – 2013-03-22 03:53:55

+2

@ FrancisR.Griffiths-Keam,你错了。从.NET 4开始,IEnumerable 与T是协变的,这意味着只要X派生自(或实现)T,IEnumerable 就可以被替换。 – 2013-03-22 04:07:37

+0

@AnthonyPegram Ahh我错过了那个备忘录,谢谢你的记录。 – 2013-03-22 04:10:54

相关问题