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 T
s but doesn't produce them. An object which can compare any two Animal
s can be used to compare two Dog
s.
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
}