C# Language Invariance


IList<T> is never a subtype of a different IList<T1>. IList is invariant in its type parameter.

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

IList<Dog> dogs = new List<Dog>();
IList<Animal> animals = dogs;  // type error

There is no subtype relationship for lists because you can put values into a list and take values out of a list.

If IList was covariant, you'd be able to add items of the wrong subtype to a given list.

IList<Animal> animals = new List<Dog>();  // supposing this were allowed...
animals.Add(new Giraffe());  // ... then this would also be allowed, which is bad!

If IList was contravariant, you'd be able to extract values of the wrong subtype from a given list.

IList<Dog> dogs = new List<Animal> { new Dog(), new Giraffe() };  // if this were allowed...
Dog dog = dogs[1];  // ... then this would be allowed, which is bad!

Invariant type parameters are declared by omitting both the in and out keywords.

interface IList<T> { /* ... */ }