大象:动物......
IList<Elephant> elephants = new List<Elephant>();
IEnumerable<Animal> animalList = elephants;
这很好但是..
IList<Elephant> elephants = new List<Elephant>();
IList<Animal> animalList = elephants;
抛出错误。这是为什么?
答案 0 :(得分:11)
如果这个
IList<Elephant> elephants = new List<Elephant>();
IList<Animal> animalList = elephants;
有可能你可以这样做
animalList.Add(new Animal());
但animalList
实际上是对elephants
引用相同的引用。由于elephants
是IList<Elephant>
,因此您尝试将Animal
的实例添加到只能包含Elephant
实例的集合中。
IEnumerable<T>
可能的原因是类型参数IEnumerable<T>
中的T
为covariant。这是因为T
仅出现在界面IEnumerable<T>
中的“out”位置。由于您只使用T
中IEnumerable<T>
的实例,因此可以安全地将IEnumerable<Derived>
的实例分配给IEnumerable<Base>
类型的变量。 IEnumerable<Derived>
中出现的任何内容都是Base
,这就是为什么实现IEnumerable<Derived>
的内容可以安全地用作IEnumerable<Base>
的原因。这就是将IEnumerable<Elephant>
的实例分配给IEnumerable<Animal>
类型的变量的安全原因。
但是你遇到了IList<T>
的问题,因为IList<T>
在类型参数T
中不是协变的。这里的问题是T
出现在界面IList<T>
的“in”位置。因此,如果您可以将IList<Derived>
的实例分配给IList<Base>
类型的变量,那么您可以尝试将Base
的实例粘贴到IList<Base>
中,而Base
实际上会尝试粘贴实例将IList<Derived>
放入IList<Elephant>
的实例中,这显然不安全。这正是我们刚刚遇到IList<Animal>
和IList<T>
的问题。
请注意,T
在类型参数T
中也不具有逆变性。这是因为IList<T>
出现在界面IList<Base>
的“out”位置。如果您可以将IList<Derived>
的实例分配给Derived
类型的变量,那么您可以尝试从IList<Derived>
中抓取Derived
的实例,该实例会尝试获取<{1}}实例中的实例IList<Base>
,这显然是荒谬的。
答案 1 :(得分:1)
这称为协方差和逆转。
我不会详细介绍,但你可以read about it。