С учетом того, что все элементы в массиве myShapes
Shape
, вы знаете, что все они поддерживают один и тот же "полиморфный интерфейс" (или, говоря проще, все они имеют метод Draw()
). Во время итерации по массиву ссылок Shape
исполняющая система самостоятельно определяет лежащий в основе тип элемента. В этот момент и вызывается корректная версия метода Draw()
.Такой прием также делает простым безопасное расширение текущей иерархии. Например, пусть вы унаследовали от абстрактного базового класса Shape
Triangle
, Square
и т.д.). Благодаря полиморфному интерфейсу код внутри цикла foreach
не потребует никаких изменений, т.к. компилятор обеспечивает помещение внутрь массива myShapes
только совместимых с Shape
типов.Сокрытие членов
Язык C# предоставляет возможность, которая логически противоположна переопределению методов и называется
В целях иллюстрации предположим, что вы получили от коллеги на доработку класс по имени ThreeDCircle
Draw()
, не принимающий аргументов:class ThreeDCircle
{
public void Draw()
{
Console.WriteLine("Drawing a 3D Circle");
}
}
Вы полагаете, что ThreeDCircle
Circle
, поэтому решаете унаследовать его от своего существующего типа Circle
:class ThreeDCircle : Circle
{
public void Draw()
{
Console.WriteLine("Drawing a 3D Circle");
}
}
После перекомпиляции вы обнаружите следующее предупреждение:
'ThreeDCircle.Draw()' hides inherited member 'Circle.Draw()'. To make
the current member
override that implementation, add the override keyword.
Otherwise add the new keyword.
'Shapes.ThreeDCircle.Draw()
Shapes.Circle.Draw()
.override
new
Дело в том, что у вас есть производный класс (ThreeDCircle
Draw()
в дочернем классе, добавив ключевое слово override
(как предлагает компилятор). При таком подходе у типа ThreeDCircle
появляется возможность расширять стандартное поведение родительского типа, как и требовалось. Однако если у вас нет доступа к файлу кода с определением базового класса (частый случай, когда приходится работать с множеством библиотек от сторонних поставщиков), тогда нет и возможности изменить метод Draw()
, превратив его в виртуальный член.В качестве альтернативы вы можете добавить ключевое слово new
Draw()
своего производного типа (ThreeDCircle
). Поступая так, вы явно утверждаете, что реализация производного типа намеренно спроектирована для фактического игнорирования версии члена из родительского типа (в реальности это может оказаться полезным, если внешнее программное обеспечение каким-то образом конфликтует с вашим программным обеспечением).// Этот класс расширяет Circle и скрывает унаследованный метод Draw().
class ThreeDCircle : Circle
{
// Скрыть любую реализацию Draw(), находящуюся выше в иерархии.
public new void Draw()
{
Console.WriteLine("Drawing a 3D Circle");
}
}
Вы можете также применить ключевое слово new
ThreeDCircle
необходимо скрыть унаследованное свойство PetName
:class ThreeDCircle : Circle
{
// Скрыть свойство PetName, определенное выше в иерархии.