如何列出<;派生类>;被分配给IEnumerable<;基类>;参数

本文关键字:gt lt IEnumerable 基类 分配 参数 何列出 派生 | 更新日期: 2023-09-27 18:20:13

我知道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
   {...}
}

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

如何列出<;派生类>;被分配给IEnumerable<;基类>;参数

因为IEnumerable<T>的声明实际上是:

public interface IEnumerable<out T> : IEnumerable

并且CCD_ 4比特表示CCD_。

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

IListList没有将它们的T定义为out,而IEnumerable定义为。List是一个类,因此不能有out,而IList不定义out,因为它接受类型为T的输入。

简单地说,你只能从IEnumerable返回T,但你可以将T放入IList,因为IEnumerable不在乎你是否不那么具体,但IList在乎。(事实上,这是必须的,请参阅@ChrisShain的回答,了解协方差和反方差是如何工作的)。

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

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>只提供读取集合的方法,而不提供对集合的写入,因此不可能出现上述矛盾。

因为IEnumerable对于类型参数T是协变的:http://geekswithblogs.net/abhijeetp/archive/2010/01/10/covariance-and-contravariance-in-c-4.0.aspx