Reputation: 990
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?
Upvotes: 0
Views: 735
Reputation: 241701
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.
Upvotes: 11
Reputation: 19743
This is called covariance and contravariance.
I won't go into details but you can read about it.
Upvotes: 1