关于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