2012-01-12 51 views
4

我知道派生类的列表<>不能直接分配给基类的列表<>。但是它如何允许将派生类的相同列表<>分配给IEnumerable类型的基类参数。如何将List <DerivedClass>分配给IEnumerable <BaseClass>参数?

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的实施和支持索引和修改的元素,但我似乎不明白这个部分?有人可以解释吗? 谢谢。

+0

请参阅[协方差和反变量](http://blogs.msdn.com/b/csharpfaq/archive/2010/02/16/covariance-and-contravariance-faq.aspx) – Magnus 2012-01-12 21:42:48

回答

7

由于IEnumerable<T>is in fact的声明:

public interface IEnumerable<out T> : IEnumerable 

...和out位意味着T是协变,并接受亚型。

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

2

IListList不明确自己Tout,而IEnumerable一样。 List是一类,所以不能有out,IList没有定义out,因为它接受T类型的输入。

把一个简单的方法,你只能拿回TIEnumerable,但你可以把TIList,因为这IEnumerable的,如果你不太具体不关心,但IList一样。 (实际上它必须,请参阅@ ChrisShain的答案,了解协变性和逆变性如何工作的链接)。

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>只提供方法来读取集合,而不是写入它,所以上述矛盾不会发生。

相关问题