C# 6.0 in a Nutshell by Joseph Albahari and Ben Albahari (O’Reilly).
Copyright 2016 Joseph Albahari and Ben Albahari, 978-1-491-92706-9.
states, at pages 123-124, with regards to type covariance:
Arrays, for historical reasons, array types support covariance. This means that B[] can be cast to A[] if B subclasses A (and both are reference types).
For example:
Bear[] bears = new Bear[3];
Animal[] animals = bears; // OK
The downside of this reusability is that element assignments can fail at runtime:
animals[0] = new Camel(); // Runtime error
What is the reason behind such error ? If you assign an instance of Bear to an instance of Animal, a runtime error will be thrown ? I do not see why it should (by allowing such an assignment, the compiler needs to take responsibility in stating "all right, I will let you do with this object everything that an animal can do." Since Bear is an animal, this incurs no problems whatsoever.
I created my own scenario to test the above:
public class X
{
public int Num { get; set; }
public void Method_1()
{
Console.WriteLine("X");
}
public virtual void Method_2()
{
Console.WriteLine(Num);
}
}
public class Y : X
{
public Y()
{
Num = 1000;
}
}
X[] arrayX = new X[] { new X { Num = 1000 }, new X { Num = 999 }, new X { Num = 51762 } };
Y[] arrayY = new Y[] { new Y { Num = 5 }, new Y { Num = 6 }, new Y { Num = 7 } };
X x = new X { Num = 1000 };
Y y = new Y { Num = 50 };
x = y;
arrayX = arrayY;
arrayX[2] = new Y { Num = 1 };
// will print 5,6,1 - no runtime errors faced
foreach (var e in arrayX)
Console.WriteLine(e.Num);
I believe the snippet above mimics the book's example - but with my snippet, there are no runtime errors.
What am I missing ? How is animals[0] = new Camel();
supposed to thrown a runtime error, as the book states ?
What is the reason behind such error?
Because it is trying to store a Camel
into an array with a runtime type of Bear[]
. An array of type Bear[]
can only store references to instances of Bear
or subclasses. The compile-time type of Animal[]
only says that it might be able to store a Camel
reference, and that any reference you get out of the array will definitely be an Animal
instance or subclass.
Your example is different. When we strip out all the properties etc (which are irrelevant) you've got:
X[] arrayX = new Y[3];
arrayX[2] = new Y();
That's fine - that's storing a reference to a Y
object in an array with an execution-time type of Y[]
. No problem.
To demonstrate the same problem as the book, you'd need a third class:
class Z : X {}
X[] arrayX = new Z[3];
arrayX[2] = new Y(); // Bang - can't store a Y reference in a Z[]
See more on this question at Stackoverflow