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.
This works just because it is a special feature that is part of the CLR. Arrays are automatically covariant even though technically they aren't. Compilers just have to know this and generate the proper type checks.
Although some consider this feature a mistake, it was very important to have prior to typesafe collections and generic interface covariance. You would not even be able to write a function to sort an array without it.
Eric explained it very clearly here: http://blogs.msdn.com/b/ericlippert/archive/2007/10/17/covariance-and-contravariance-in-c-part-two-array-covariance.aspx.
Short resume: if D inherits B then D[] is covariant to B[]. Assume D2 also inherits from B, then
B[] b = new D[10];
b[0] = new D1();
throws exception. Yes, this is not good but it is so.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With