#1,147 – Why Generics Don’t Support Covariance
July 28, 2014 6 Comments
In C#, arrays support covariance, but generics do not. Generics aren’t covariant in order to avoid the problem that we have with covariant arrays. With arrays, we get type mismatch exceptions when trying to put something into the array of the wrong type. The core problem here is that the array looks syntactically like an array of the base type, but is actually an array of the more derived type.
Generics in C# aren’t covariant in order to avoid this same problem. The language designers decided to support covariance for arrays but not for generics. The reasons are likely more historical than technical.
// Array covariance--OK Dog[] dogs = new Terrier[5]; // The problem with array covariance. // Compiler allows, but throws ArrayTypeMismatchException // at run-time dogs[0] = new BorderCollie("Shep"); // Generic covariance--not allowed (compiler error) List<Dog> moreDogs = new List<Terrier>();
Pingback: Dew Drop – July 28, 2014 (#1823) | Morning Dew
Eric Lippert describes why arrays were made to support covariance here:
http://blogs.msdn.com/b/ericlippert/archive/2007/10/17/covariance-and-contravariance-in-c-part-two-array-covariance.aspx
He does note how unhappy he was about the decision.
Again, generics can be covariant or contravariant. The reason List is not is because the type must go both directions; a generic readonly collection, or a generic IEnumerable or Action or Func can all be variant.
Generic interfaces and delegates support variance, but generic types do not.
Ah; I think it’s clearer to say generic classes and structs are the only generic types which are invariant. Types (I believe) can be interface types, delegate types, enums, etc.
The reason throwing ArrayTypeMismatchException at run-time is because the actual type of dogs[0] is Terrier.