Язык программирования C#9 и платформа .NET5
С учетом того, что все элементы в массиве
на самом деле являются производными от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:Circleclass ThreeDCircle : Circle{public void Draw(){Console.WriteLine("Drawing a 3D Circle");}}После перекомпиляции вы обнаружите следующее предупреждение:
'ThreeDCircle.Draw()' hides inherited member 'Circle.Draw()'. To makethe current memberoverride 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:PetNameclass ThreeDCircle : Circle{// Скрыть свойство PetName, определенное выше в иерархии.public new string PetName { get; set; }// Скрыть любую реализацию Draw(), находящуюся выше в иерархии.public new void Draw(){Console.WriteLine("Drawing a 3D Circle");}}Наконец, имейте в виду, что вы по-прежнему можете обратиться к реализации скрытого члена из базового класса, используя явное приведение, как описано в следующем разделе. Вот пример: