In .NET 4.0 Microsoft presented covariance (out) and contravarince (in). Next image shows simple class hierarchy:
Imagine there is a need of animal container class that can only return data
interface IAnimalHub<T> where T: Animal { T GetAnimal(); }We can declare and work with animal hub type as
IAnimalHub<Animal> hub1 = new AnimalHub<Animal>();
Can we generalise left part or, in other word, downgrade type
IAnimalHub<Animal> hub2 = new AnimalHub<Lion>(); IAnimalHub<Animal> hub3 = new AnimalHub<Cat>();
Definitely it is possible, because we are going only to take out data and work with it, whether it is Lion or Cat. This idea is called covariance and can be done with out keyword in C#:
interface IAnimalHub<out T> where T: Animal { T GetAnimal(); }
Now what if we have Add method with some animal argument in addition to our Get method
interface IAnimalHub<out T> where T: Animal { T GetAnimal(); void Add(T animal); }
Should it work?
No! And the reason is that otherwise it would be possible to do
IAnimalHub<Lion> hub = new AnimalHub<Lion>(); var dog = new Dog(); hub.Add(dog);
So one cannot expect possibility to Add dog while waiting Lion object. It means covariance works only with returning data (out).
What about contrvarience?
As the word says this works in the opposite to covariance. Contrvariance expects only methods where one can put/write/insert data. In C# this is presented with in keyword. Consider only Add method in our interface:interface IAnimalHub<in T> where T: Animal { void Add(T animal); }
Now we can do the opposite
IAnimalHub<Animal> hub1 = new AnimalHub<Animal>(); IAnimalHub<Lion> hub2 = new AnimalHub<Animal>(); IAnimalHub<Cat> hub3 = new AnimalHub<Animal>(); IAnimalHub<Dog> hub4 = new AnimalHub<Animal>();
In other words we can put Lion, Cat or Dog object where we expect Animal.
Limitations
Covariance and contrvariance can be declared only in the interface or delegate, not class. Generic parameter can be only reference type, not value type.Examples
In .NET IEnumerable<T> only returns data, so it is created as covariant IEnumerable<out T> in version 4 of the framework. And we simply can doAnimal[] animals = new Lion[0]; Animal[] animals = new Cat[0]; IEnumerable<Animal> animals = new Lion[0]; IEnumerable<Animal> animals = new Cat[0];