Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
26
Добавлен:
29.02.2016
Размер:
69.59 Кб
Скачать

Сокрытие методов

Если методы с одинаковой сигнатурой объявлены и в базовом, и в унаследованном клас­се, но при этом не указаны, соответственно, как virtual и override, то говорят, что вер­сия метода в классе-наследнике скрывает версию метода базового класса.

В большинстве случаев требуется переопределять методы, а не скрывать их. Скрывая методы, вы рискуете вызывать "неверный" метод для экземпляра данного класса. Однако, как показано в следующем примере, синтаксис С# спроектирован так, чтобы гарантиро­вать, что разработчик будет предупрежден об этой потенциальной проблеме во время ком­пиляции, тем самым обеспечивая возможность более безопасного сокрытия методов, если это действительно нужно. Это также дает преимущества разработчикам библиотек классов при работе с разными версиями.

Предположим, что имеется класс HisBaseClass:

class HisBaseClass

{

// разнообразные члены

}

В какой-то момент в будущем вы напишете класс-наследник, добавляющий некоторую функциональность к HisBaseClass. В частности, добавите метод MyGroovyMethod(), которого нет в базовом классе:

class MyDerivedClass: HisBaseClass

{

public int MyGroovyMethod()

{

// некая превосходная реализация

return 0;

}

}

Годом позже вы решите расширить функциональность базового класса. Случайно вы добавите метод, также именуемый MyGroovyMethod(), имеющий то же имя и сигнатуру, что и в наследнике, но, возможно, решающий какую-то другую задачу. Компилируя код, использующий новую версию базового класса, чвы получаете потенциальный конфликт, поскольку программа не знает, какой именно метод вызывать. Это совершенно коррект­но с точки зрения С#, но поскольку ваш MyGroovyMethod() никак не связан с версией MyGroovyMethod() из базового класса, то при запуске этого кода вы не получите того, чего ожидали. К счастью, язык С# спроектирован так, что прекрасно справляется с кон­фликтами подобного рода.

В таких случаях при компиляции С# генерирует предупреждение. Оно напомнит о не­обходимости применения ключевого слова new при выражении намерения сокрыть метод базового класса:

class MyDerivedClass: HisBaseClass

{

public new int MyGroovyMethod()

{

// некая превосходная реализация

return 0;

}

}

Но поскольку версия MyGroovyMethod() не объявлена как new, компилятор укажет на тот факт, что она скрывает метод базового класса, несмотря на отсутствие указания делать это, выдав предупреждение (это произойдет независимо от того, объявлен метод MyGroovyMethod() виртуальным или нет). Если хотите, можете переименовать свою версию метода. И это будет наилучшим решением, поскольку оно исключает будущую пу­таницу. Однако если по каким-то причинам вы решите не переименовывать такой метод (например, вы поставляете свой код в виде библиотек другим компаниям, а потому не можете изменять имена методов), то весь существующий клиентский код будет работать корректно, выбирая вашу версию MyGroovyMethod(). Это объясняется тем, что любой су­ществующий код, который обращается к этому методу, должен делать это через ссылку на MyDerivedClass (или на будущий класс-наследник).

Существующий код не может обращаться к этому методу через ссылку на HisBaseClass  будет выдана ошибка при компиляции более ранней версии HisBaseClass. Проблема может возникнуть только в клиентском коде. Компилятор С# ведет себя так, что вы получаете предупреждение о потенциальных проблемах, которые могут возникнуть в будущем коде. На это предупреждение нужно обязательно обратить внимание и позабо­титься о том, чтобы не пытаться вызывать вашу версию MyGroovyMethod() через любую ссылку на HisBaseClass в любом коде, который будет написан позже. Тем не менее, весь существующий код будет работать нормально. Может показаться, что это довольно тонкий момент, но в то же время это  красноречивый пример того, как С# может справляться с разными версиями классов.

Соседние файлы в папке 04 Наследование