我理解列表<>派生类的类不能直接分配给List<>基类。但是它如何允许分配相同的List<>派生类到IEnumerable<>基类参数的类型。
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
{...}
}
我知道List
是IEnumerable
的实现,并支持索引和修改元素,但我似乎不理解这一部分?有人可以解释一下吗?
感谢。
答案 0 :(得分:7)
因为声明IEnumerable<T>
is in fact:
public interface IEnumerable<out T> : IEnumerable
...而out
位表示T
是协变的并接受子类型。
虽然List<T>
的声明没有方差注释,因此T
是不变的。
答案 1 :(得分:2)
IList
和List
未将T
定义为out
,而IEnumerable
则定义List
。 out
是一个类,因此无法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)
因为IEnumerable是类型参数T的Covariant:http://geekswithblogs.net/abhijeetp/archive/2010/01/10/covariance-and-contravariance-in-c-4.0.aspx