I was reading up on covariance and contravariance today and I came across a post on Stack Exchange where Jon Skeet was explaining invariance at the class level. He used an example of fruit and why allowing covariance at that level would be a bad thing:
//Bad
List<Banana> bunchOfBananas = new List<Banana>();
// This would be valid if List<T> were covariant in T
List<Fruit> fruitBowl = bunchOfBananas;
fruitBowl.Add(new Apple());
Banana banana = bunchOfBananas[0];
So, how does this account for having a list of Fruit
that you would add instances of class that inherit from Fruit
? For example:
//Good
List<Fruit> fruitBowl = new List<Fruit>();
fruitBowl.Add(new Apple());
fruitBowl.Add(new Banana());
I've done this in the past and it always behaves as expected. Why doesn't the CLR look at the type of fruitBowl
? Is it because you are setting the value of your fruitBowl
to a list of Banana
s first which is covariant to a list of Fruit
and then trying to add an Apple
to a collection whose type is really List<Banana>
?
I think what you are missing is that when you do in your first example:
List<Fruit> fruitBowl = bunchOfBananas;
You are not making a copy of bunchOfBananas
into a List<Fruit>
. Instead, you are creating a reference to a bunch of bananas, and that reference could be used to add any kind of fruit.
Thus when you do:
fruitBowl.Add(new Apple());
you would not be adding an apple to a list of fruit; you'd be adding an apple to the List<Banana> bunchOfBananas
, which is clearly A Bad Thing.