IList <t> vs IEnumerable <t>:为什么这个赋值无效?</t> </t>

时间:2011-02-02 04:20:21

标签: c# ienumerable

大象:动物......

IList<Elephant> elephants = new List<Elephant>();
IEnumerable<Animal> animalList = elephants;

这很好但是..

IList<Elephant> elephants = new List<Elephant>();
IList<Animal> animalList = elephants;

抛出错误。这是为什么?

2 个答案:

答案 0 :(得分:11)

如果这个

IList<Elephant> elephants = new List<Elephant>();
IList<Animal> animalList = elephants;

有可能你可以这样做

animalList.Add(new Animal());

animalList实际上是对elephants引用相同的引用。由于elephantsIList<Elephant>,因此您尝试将Animal的实例添加到只能包含Elephant实例的集合中。

IEnumerable<T>可能的原因是类型参数IEnumerable<T>中的Tcovariant。这是因为T仅出现在界面IEnumerable<T>中的“out”位置。由于您只使用TIEnumerable<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