C# Language Contravariance


When is an IComparer<T> a subtype of a different IComparer<T1>? When T1 is a subtype of T. IComparer is contravariant in its T parameter, which means that IComparer's subtype relationship goes in the opposite direction as T's.

class Animal { /* ... */ }
class Dog : Animal { /* ... */ }

IComparer<Animal> animalComparer = /* ... */;
IComparer<Dog> dogComparer = animalComparer;  // IComparer<Animal> is a subtype of IComparer<Dog>
// animalComparer = dogComparer;  // Compilation error - IComparer<Dog> is not a subtype of IComparer<Animal>

An instance of a contravariant generic type with a given type parameter is implicitly convertible to the same generic type with a more derived type parameter.

This relationship holds because IComparer consumes Ts but doesn't produce them. An object which can compare any two Animals can be used to compare two Dogs.

Contravariant type parameters are declared using the in keyword, because the parameter must be used only as an input.

interface IComparer<in T> { /* ... */ }

A type parameter declared as contravariant may not appear as an output.

interface Bad<in T>
    T GetT();  // type error