0

I'm trying to understand how covariance works (in general, though my examples will be in C#) and what governs when a generic type can be covariant. Assume we have a class Animal with subclasses Cat and Dog. I get why a read-only type such as IEnumerable<T> is covariant, allowing this code to compile:

IEnumerable<Animal> initialAnimalEnumerable = new List<Cat> {new Cat() };
IEnumerable<Animal> addedAnimalEnumerable = initialAnimalEnumerable.Append(new Dog());

because the elements of the enumerable can only be treated as type Animal; the information that they're Cats/Dogs specifically is lost. What I don't understand is why this can't apply with mutable collections such as List<T>:

List<Animal> initialAnimalList = new List<Cat> {new Cat() }; // error CS0266: Cannot implicitly convert type 'List<Cat>' to 'List<Animal>'
initialAnimalList[0] = new Dog();

Explanations on questions like C# variance problem seem to assume that this would cause a problem, because we're trying to add a Dog to a List<Cat>...but why is it still treated as a List<Cat> instead of a List<Animal>?

DylanSp
  • 1,379
  • 13
  • 27

1 Answers1

1

You're assuming a simple case where the only reference to the List<Cat> was the one used in assigning initialAnimalList. What if instead of creating a new object/reference you were instead assigning from another existing variable:

E.g.:

var cats = new List<Cat> {new Cat() };
List<Animal> initialAnimalList = cats; // error CS0266
initialAnimalList[0] = new Dog();

We still have cats. It's type hasn't magically changed to List<Animal> due to some later assignment, and any later code that accesses cats is entitled to assume it won't find a Dog in there.

The assignment doesn't change the type of the object.

Damien_The_Unbeliever
  • 234,701
  • 27
  • 340
  • 448