C# IList<;T>;vs IEnumerable<;T>;:为什么这个任务无效?
大象:动物C# IList<;T>;vs IEnumerable<;T>;:为什么这个任务无效?,c#,ienumerable,C#,Ienumerable,大象:动物 IList<Elephant> elephants = new List<Elephant>(); IEnumerable<Animal> animalList = elephants; IList=新列表(); IEnumerable animalist=大象; 这很好,但是 IList<Elephant> elephants = new List<Elephant>(); IList<Animal> an
IList<Elephant> elephants = new List<Elephant>();
IEnumerable<Animal> animalList = elephants;
IList=新列表();
IEnumerable animalist=大象;
这很好,但是
IList<Elephant> elephants = new List<Elephant>();
IList<Animal> animalList = elephants;
IList=新列表();
IList animalList=大象;
抛出一个错误。为什么呢 如果
IList<Elephant> elephants = new List<Elephant>();
IList<Animal> animalList = elephants;
但是animalList
实际上是指与大象
相同的参照物。由于大象
是一个IList
,您将尝试向只能包含大象
实例的集合中添加动物
的实例
之所以可以使用IEnumerable
,是因为IEnumerable
位于类型参数T
中。这是因为T
仅出现在接口IEnumerable
中的“out”位置。由于您只使用IEnumerable
中的T
实例,因此可以安全地将IEnumerable
实例分配给IEnumerable
类型的变量。任何来自IEnumerable
的东西都是Base
,这就是为什么实现IEnumerable
的东西可以安全地用作IEnumerable
的原因。这就是为什么将IEnumerable
的实例分配给IEnumerable
类型的变量是安全的
但是您在使用IList
时遇到了麻烦,因为IList
在类型参数T
中是不协变的。这里的问题是T
出现在界面IList
的“in”位置。因此,如果您可以将IList
的实例分配给IList
类型的变量,那么您可以尝试将Base
的实例粘贴到IList
中,这实际上是试图将Base
的实例粘贴到IList
的实例中,这显然是不安全的。这正是我们刚才在使用IList
和IList
时遇到的问题
请注意,
IList
在类型参数T
中也不是逆变的。这是因为T
出现在界面IList
的“out”位置。如果您可以将IList
的实例分配给IList
类型的变量,那么您可以尝试从IList
中获取Derived
的实例,这将试图从IList
的实例中获取Derived
,这显然是荒谬的。这被称为协方差和反方差
我不会详细介绍,但您可以。请注意,
Derived[]
可以用作Base[]
,插入Derived
将引发异常。这是因为.NET继承了数组variance周围被破坏的Java规则
animalList.Add(new Animal());