Рейтинговые книги
Читем онлайн Язык программирования C#9 и платформа .NET5 - Троелсен Эндрю

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 139 140 141 142 143 144 145 146 147 ... 642

С учетом того, что все элементы в массиве 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.

(window.adrunTag = window.adrunTag || []).push({v: 1, el: 'adrun-4-390', c: 4, b: 390})

В противном случае добавьте ключевое слово 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, определенное выше в иерархии.

   public new string PetName { get; set; }

  // Скрыть любую реализацию Draw(), находящуюся выше в иерархии.

  public new void Draw()

  {

    Console.WriteLine("Drawing a 3D Circle");

  }

}

Наконец, имейте в виду, что вы по-прежнему можете обратиться к реализации скрытого члена из базового класса, используя явное приведение, как описано в следующем разделе. Вот пример:

1 ... 139 140 141 142 143 144 145 146 147 ... 642
На этой странице вы можете бесплатно читать книгу Язык программирования C#9 и платформа .NET5 - Троелсен Эндрю бесплатно.
Похожие на Язык программирования C#9 и платформа .NET5 - Троелсен Эндрю книги

Оставить комментарий