Covariant and contravariant
Convention:
A ≦ B
That means A is A subtype of BA and B
Refers to A function type that takes A as its argument type and B as its return value typex : A
That means x is of type A
The concepts of covariant and contravariant can be understood with the aid of actual variable types:
- Covariant and ordinary variables:
In C#, the List class implements IEnumerable, so List implements IEnumerable:
IEnumerable<Derived> d = new List<Derived>();
IEnumerable<Base> b = d;
Copy the code
Simply put, covariant, like polymorphism in object-oriented concepts, refers to a situation in which a parent type reference can be used to point to an instance of a child type.
- Contravariant and function variables:
If I have A type chain C ≦ B ≦ A, and A function f(B → B) takes A function B → B as an argument, what function can be used as an argument to f?
First, this is not possible for C → *, because f may call a function with arguments of type B or other subtypes of B, while C → * only supports input arguments of type C.
Then, it is also not possible for * → A, since f requires that the return value be B or some other subtype of B, but * → A may return B’s parent type A.
Finally, it is feasible for A → C, because f’s argument will only be B or some other subtype of B, and A → C’s input type will be A, satisfying. Meanwhile, the return value of function A → C is C, which is A subtype of B, and the return value type also satisfies.
Here, the magic happens. When the function type is B → B, we can use
–
to assign:
Action<Base> b = (target) => { Console.WriteLine(target.GetType().Name); };
Action<Derived> d = b;
Copy the code
This is contravariant.
Reference:
- Covariant and contravariant – Wikipedia, the free encyclopedia
- Generic covariant and inverter in | Microsoft Docs
- Covariance and inverter | deep understanding of the TypeScript