In C#, covariant and contravariant allow implicit conversion for generic type arguments. But they're not applied to struct or other value types including primitive type (except string) and enum.
Only an interface declaration can contain covariant and contravariant generic parameters.
A covariant allows to assign an object that is instantiated with a more derived type argument to an object that is instantiated with a less derived type argument. It's declared with keyword out
with the generic type parameter. For example, this declares an interface with a covariant generic parameter: interface ICovariantInterface<out T>
.
A contravariant does the reversed. It allows to assign an object that is instantiated with a less derived type argument to an object that is instantiated with a more derived type argument. It's declared with keyword in
with the generic type parameter. For example, this declares an interface with a contravariant generic parameter: interface IContravariantInterface<in T>
.
There are some built-in covariant and contravariant generic interfaces in C#, such as IEnumerable, IComparable.
Usually I would think that covariant in analogy to class hierarchy. It's similar to that a derived class can be assigned to a base class/interface. For contravariant, it's done in the opposite direction.
But we cannot use struct or other value types in covariant and contravariant. Both covariant and contravariant are applied to reference types. And reference types and value types have different memory layout.
So this is not allowed: IEnumerable<object> baseGeneric = new List<int>();
.