Приведение производного члена базового массива в С#

У меня есть базовый класс Shape с двумя производными классами Circle и Rectangle. Теперь я написал явные преобразования из Rectangle в Circle и наоборот. Они не имеют особого смысла, но сейчас я не об этом. Я создаю новые экземпляры Rectangle и Circle и хочу назначить Rectangle экземпляру Circle с приведением. Это работает, как и ожидалось.

Но если у меня есть массив типа Shape, который заполнен Rectangles, и я хочу преобразовать член массива, он выдает System.InvalidCastException. Поскольку я написал явные приведения, я не знаю, почему это невозможно.

Shape[] arr = new Shape[5];

Circle c1 = new Circle(1, 2, 3);
Circle c2 = new Circle(4, 5, 6);
Rectangle r1 = new Rectangle(7, 8);
Rectangle r2 = new Rectangle(9, 10);
Shape c3 = new Circle(3, 9, 13);

arr[0] = c1;
arr[1] = c2;
arr[2] = r1;
arr[3] = r2;
arr[4] = c3;


Console.WriteLine(r1.GetType());
Console.WriteLine(arr[2].GetType()); // both evalute to Rectangle

Circle r3 = (Circle)r1;             // compiles
Circle r4 = (Circle)arr[2];         // Unhandled Exception

Итак, как указал Ондржей, это приведение формы к кругу, что недопустимо. Однако Ингвар отметил, что это работает:

Circle r5 = (Circle)((Rectangle)arr[2]);    
Rectangle r6 = (Rectangle)((Circle)arr[0]);

и это не

Circle r5 = (Circle)arr[2];   
Rectangle r6 = (Rectangle)arr[0];

Спасибо за вашу помощь!


person brandbenni    schedule 01.04.2019    source источник


Ответы (2)


Вы напрямую переводите элемент массива Shape в Circle, это невозможно, потому что на самом деле ваш объект Rectangle. Попробуйте явное приведение:

Circle r4 = (Circle)((Rectangle)arr[2]);
person ingvar    schedule 01.04.2019
comment
Это работает, но почему я могу выполнить приведение к прямоугольнику, если я не могу выполнить приведение к кругу? Это оба класса, производные от Shape, или я что-то упустил? - person brandbenni; 01.04.2019
comment
С# не имеет пониженного приведения. Вы не можете напрямую привести объект базового типа к объекту дочернего типа, за исключением случаев, когда компилятор знает этот тип элемента. В вашем случае компилятор знает, что ваш элемент Rectangle, поэтому он позволяет преобразовать его в Rectangle - person ingvar; 01.04.2019

Circle r4 = (Circle)arr[2];

Компилятор не может применить явное приведение, потому что он не может статически определить, что arr[2] на самом деле хранит Rectangle. Для компилятора это Shape и, следовательно, (Circle)arr[2] — это приведение от Shape к Circle.

person Ondrej Tucny    schedule 01.04.2019
comment
Это кажется логичным, но я не могу написать явное приведение от Shape к Circle. Значит, мой подход просто невозможен? - person brandbenni; 01.04.2019
comment
Позвольте мне предложить вам обновить ваш вопрос, включая все объявления, включая явные приведения, и предоставить минимальный воспроизводимый пример. - person Ondrej Tucny; 01.04.2019
comment
Спасибо за вашу помощь, и я думаю, что теперь я понял. Поскольку программа знает, что arr[2] — это прямоугольник, я могу преобразовать его из Shape в Rectangle, а затем из Rectangle в Circle. Первое приведение на самом деле не является приведением, оно просто работает, потому что arr[2] уже является прямоугольником. - person brandbenni; 01.04.2019
comment
Вот и все. В любом случае, не стесняйтесь публиковать более полный пример, и мы можем обсудить его дальше. - person Ondrej Tucny; 01.04.2019