I\'m having a little trouble understanding how I would use covariance and contravariance in the real world.
So far, the only examples I\'ve seen have been the same o
In the real world, you can always use a shelter for animals instead of a shelter for rabbits because every time an animal shelter hosts a rabbit it is an animal. However, if you use a rabbit shelter instead of an animal shelter its staff can get eaten by a tiger.
In code, this means that if you have an IShelter
you can simply write IShelter
if you promise and use T
in the IShelter
only as method parameters like so:
public class Contravariance
{
public class Animal { }
public class Rabbit : Animal { }
public interface IShelter
{
void Host(T thing);
}
public void NoCompileErrors()
{
IShelter animals = null;
IShelter rabbits = null;
rabbits = animals;
}
}
and replace an item with a more generic one, i.e. reduce the variance or introduce contravariance.
In the real world, you can always use a supplier of rabbits instead of a supplier of animals because every time a rabbit supplier gives you a rabbit it is an animal. However, if you use an animal supplier instead of a rabbit supplier you can get eaten by a tiger.
In code, this means that if you have an ISupply
you can simply write ISupply
if you promise and use T
in the ISupply
only as method return values like so:
public class Covariance
{
public class Animal { }
public class Rabbit : Animal { }
public interface ISupply
{
T Get();
}
public void NoCompileErrors()
{
ISupply animals = null;
ISupply rabbits = null;
animals = rabbits;
}
}
and replace an item with a more derived one, i.e. increase the variance or introduce covariance.
All in all, this is just a compile-time checkable promise from you that you would treat a generic type in a certain fashion to keep the type safety and not get anyone eaten.
You might want to give this a read to double-wrap your head around this.