#1,147 – Why Generics Don’t Support Covariance

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>();

About Sean
Software developer in the Twin Cities area, passionate about software development and sailing.

6 Responses to #1,147 – Why Generics Don’t Support Covariance

  1. Pingback: Dew Drop – July 28, 2014 (#1823) | Morning Dew

  2. 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.

  3. Joseph says:

    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.

    • Sean says:

      Generic interfaces and delegates support variance, but generic types do not.

      • Joseph says:

        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.

  4. Steve says:

    The reason throwing ArrayTypeMismatchException at run-time is because the actual type of dogs[0] is Terrier.

Leave a comment