简体   繁体   中英

IList<T> vs IEnumerable<T>: Why is this assignment invalid?

Elephant : Animal....

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

this works fine but..

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

throws an error. Why is that?

If this

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

were possible you could then do this

animalList.Add(new Animal());

but animalList is really a reference to the same referrent as elephants . And since elephants is an IList<Elephant> you'd be trying to add an instance of Animal to an collection that can only contain instances of Elephant .

The reason that it is possible for IEnumerable<T> is that IEnumerable<T> is covariant in the type parameter T . This is because T only appears in "out" positions in the interface IEnumerable<T> . Since you're only consuming instances of T from the IEnumerable<T> , it is safe to assign instances of IEnumerable<Derived> to variables of type IEnumerable<Base> . Anything that comes out of IEnumerable<Derived> is a Base and this is why something that implements IEnumerable<Derived> can be used as a IEnumerable<Base> safely. This is why it is safe to assign an instance of IEnumerable<Elephant> to a variable of type IEnumerable<Animal> .

But you get in trouble with IList<T> because IList<T> is not covariant in the type parameter T . The issue here is that T appears in "in" positions in the interface IList<T> . So if you could assign instances of IList<Derived> to variables of type IList<Base> , then you could try to stick instances of Base into the IList<Base> which would really be trying to stick instances of Base into an instance of IList<Derived> and that is clearly not safe to do. This is exactly the issue that we just ran into with IList<Elephant> and IList<Animal> .

Note that IList<T> is also not contravariant in the type parameter T . This is because T appears in "out" positions in the interface IList<T> . If you could assign instances of IList<Base> to a variable of type IList<Derived> then you could try to grab an instance of Derived out of the IList<Derived> which would be trying to grab an instance Derived out of an instance of IList<Base> and that is clearly absurd.

This is called covariance and contravariance .

I won't go into details but you can read about it .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM