如何将List <derivedclass>分配给IEnumerable <baseclass>参数?</baseclass> </derivedclass>

时间:2012-01-12 21:38:48

标签: c# list

我理解列表&lt;&gt;派生类的类不能直接分配给List&lt;&gt;基类。但是它如何允许分配相同的List&lt;&gt;派生类到IEnumerable&lt;&gt;基类参数的类型。

public class Base 
{}

public class Derived : Base 
{}

public class Test
{
   // inside some method...
   List<Derived> someElements;
   ReadElements(someElements);

   public void ReadElements(List<Base> elements) // this throws compile error
   {...} 

   public void ReadElements(IEnumerable<Base> elements) // this one works
   {...}
}

我知道ListIEnumerable的实现,并支持索引和修改元素,但我似乎不理解这一部分?有人可以解释一下吗? 感谢。

4 个答案:

答案 0 :(得分:7)

因为声明IEnumerable<T> is in fact

public interface IEnumerable<out T> : IEnumerable

...而out位表示T是协变的并接受子类型。

虽然List<T>的声明没有方差注释,因此T是不变的。

答案 1 :(得分:2)

IListList未将T定义为out,而IEnumerable则定义Listout是一个类,因此无法IList,而out未定义T,因为它接受T类型的输入。

更简单一点,您只能从IEnumerable返回T,但是您可以IList加入IEnumerable,因为IList没有如果你不那么具体,那就要关心,但{{1}}确实如此。 (事实上​​,它必须,请参阅@ ChrisShain的答案,以获得协方差和逆变工作方式的链接)。

答案 2 :(得分:2)

考虑一下这段代码,它本身是完全合法的:

public void AddElements(List<Base> elements)
{
    Base item = new Base();
    elements.Add(item);
}

但如果你这样称呼它会发生什么:

List<Derived> elements = new List<Derived>;
AddElements(elements);

班级Base不会从Derived继承,因此无法添加到elements列表中。这是一个潜在的问题,因此是非法的。

另一方面,IEnumerable<Base>仅提供读取集合的方法,而不是写入集合,因此上述矛盾不会发生。

答案 3 :(得分:1)