It is clear that the T[] array type is not covariant as the elements of a T[] can be set by index.
And yet, a U[] can be cast to a T[] without any complaints from the compiler as long as U derives from T.
Man[] men = new[] { new Man("Aaron"), new Man("Billy"), new Man("Charlie") };
Person[] people = (Person[])men;
In the above code it appears that men and people do seem to hold a reference to the same Array object. The effect of setting men[0] = new Man("Aidan") can be seen at people[0]. Similarly attempting people[0] = new Woman("Debbie") results in an ArrayTypeMismatchException at runtime*.
Does this mean that the T[] type actually performs type checking on every set call? It seems that this must be necessary if it is allowed to cast arrays in this manner.
I guess my question is just: How is this possible? It’s clear to me that U[] does not derive from T[]. It’s also unclear to me whether I could ever define my own type that would work in this way: actually be invariant but act covariant.
*Though array variance is apparently permitted by the CLR, any language could disallow casting between array types. However, it appears that this behavior is identical in VB.NET:
Dim men = New Man() { New Man("Aaron"), New Man("Billy"), New Man("Charlie") }
Dim people = CType(men, Person())
This is a special behavior of arrays and cannot be replicated in any other type.
It is generally regarded as a mistake.