Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/csharp-4.0/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
关于C#协方差的问题_C#_C# 4.0_Covariance - Fatal编程技术网

关于C#协方差的问题

关于C#协方差的问题,c#,c#-4.0,covariance,C#,C# 4.0,Covariance,在下面的代码中: interface I1 { } class CI1: I1 { } List<CI1> listOfCI1 = new List<CI1>(); IEnumerable<I1> enumerableOfI1 = listOfCI1; //this works IList<I1> listofI1 = listOfCI1; //this does not 接口I1{} 类CI1:I1{} List listOfCI1=新列

在下面的代码中:

interface I1 { }
class CI1: I1 { }

List<CI1> listOfCI1 = new List<CI1>();

IEnumerable<I1> enumerableOfI1 = listOfCI1; //this works

IList<I1> listofI1 = listOfCI1; //this does not
接口I1{}
类CI1:I1{}
List listOfCI1=新列表();
IEnumerable enumerableOfI1=listOfCI1//这很有效
IList listofI1=listofI1//这是不可能的
我能够将我的“listOfCI1”分配给一个
IEnumerable
(由于协方差)

但是为什么我不能将它分配给
IList
? 就这一点而言,我甚至无法做到以下几点:

List<I1> listOfI12 = listOfCI1;
List listOfI12=listofi1;
协方差不应该允许我将派生类型分配给基类型吗?

否则,您就可以将
I1
的不同实现添加到只应包含
C1
s的列表中。

简单地说,
IList
不是协变的,而
IEnumerable
是协变的。这就是为什么

假设IList是协变的。下面的代码显然不是类型安全的。。。但是您希望错误在哪里呢

IList<Apple> apples = new List<Apple>();
IList<Fruit> fruitBasket = apples;
fruitBasket.Add(new Banana()); // Aargh! Added a Banana to a bunch of Apples!
Apple apple = apples[0]; // This should be okay, but wouldn't be
IList在上面,或者看我关于与NDC差异的演讲

基本上,方差只有在保证安全的情况下才被允许(并且以保留表示的方式,这就是为什么不能将
IEnumerable
转换为
IEnumerable
——装箱转换不保留表示)。

IList
接口不是协变的。

比较声明(msdn)

公共接口IEnumerable:IEnumerable
公共接口IList:ICollection、IEnumerable、IEnumerable

你看到那个神奇的单词了吗?这意味着协方差处于启用状态。

更具体地说,这意味着
IEnumerable
对于
T
是协方差的。接口在某些类型参数中可能是可变的,但在其他类型参数中可能是可变的。@Arnis:谢谢-我自己也很喜欢它,即使我没有播放我录制的Hokey Cokey视频…Jon,BCL团队也添加了(IEnumerable:IEnumerable),因为IEnumerable不允许您添加任何新成员(即它的不可变)以确保安全。但另一方面,没有在IList上添加“out”,因为它是可变的(这样就可以在底层列表中添加不同的实现?@Rajah:这非常正确。请注意,在IEnumerable上,每个“T”都显示在“输出”位置,而不是“输入”位置。因此,协方差为“out”,逆变换为“in”。这就是编译器和CLR如何知道变式是安全的。(实际规则要复杂一些,但这是合理的简化。)@Neme:Done。(假设你指的是视频链接)另请参见:C#在数组方面犯了一个很大的错误。
public interface IEnumerable<out T> : IEnumerable

public interface IList<T> : ICollection<T>, IEnumerable<T>, IEnumerable