Подтвердить что ты не робот

Как "правильно" переопределить метод базового класса?

Всякий раз, когда я переопределяю метод базового класса, кроме моей реализации этого метода, у меня, кажется, есть 3 варианта.

1) Назовите base.Method(), а затем укажите мою реализацию.

2) Предоставьте мою реализацию, а затем вызовите base.Method()

3) Просто предоставьте мою реализацию.

Недавно, используя библиотеку, я реализовал несколько ошибок, которые были введены из-за того, что библиотека не реализовала метод. Я не уверен, что это плохо в части библиотеки или что-то не так в моем понимании.

Я возьму один пример.

public class ViewManager {
     public virtual void Customize(){
        PrepareBaseView();
     }
}

public class PostViewManager {
     public override void Customize(){
        base.Customize();
        PreparePostView();
     }
}


public class PreViewManager {
     public override void Customize(){
        PreparePreView();
        base.Customize();
     }
}


public class CustomViewManager {
     public override void Customize(){
        PrepareCustomView();
     }
}

Мой вопрос здесь в том, как узнать класс ребенка (не рассматривая реализацию базового класса), какой порядок (или параметр) ожидается родительским классом? Есть ли способ, которым родительский класс мог принудительно применять один из трех альтернатив ко всем классам создания?

4b9b3361

Ответ 1

как может класс ребенка узнать (не обращая внимания на реализацию базового класса), какой порядок (или параметр) ожидается родительским классом?

Невозможно "знать" это, когда вы подклассифицируете и переопределяете метод. Правильная документация - это единственный вариант здесь.

Есть ли способ, в котором родительский класс может принудительно применять один из трех альтернатив ко всем классам-получателям?

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

public class BaseClass {
    public void Method() // Non-virtual
    {
          // Do required work

          // Call virtual method now...
          this.OnMethod();
    }

    protected virtual void OnMethod()
    { // Do nothing
    }
 }

Подклассы могут затем "переопределять" OnMethod и предоставлять функциональные возможности, которые происходят после работы "метода".

Причиной этого является то, что виртуальные методы предназначены для того, чтобы подкласс полностью заменил реализацию родительского класса. Это делается специально. Если вы хотите предотвратить это, лучше сделать метод не виртуальным.

Ответ 2

Вот почему я чувствую, что виртуальные методы опасны, когда вы отправляете их в библиотеке. Правда, вы никогда не знаете, не глядя на базовый класс, иногда вам приходится запускать рефлектор, читать документацию или подходить к ней с проб и ошибок.

При написании кода я всегда устал следовать правилу, которое гласит:

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

Это взято из http://msdn.microsoft.com/en-us/library/ms229011.aspx, однако это для дизайна событий, хотя я считаю, что прочитал это в книге "Руководства по дизайну Framework" (http://www.amazon.com/Framework-Design-Guidelines-Conventions-Libraries/dp/0321246756).

Однако это, очевидно, не так, например, веб-формы ASP.NET требуют базового вызова на странице_Load.

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

Ответ 3

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

Технически эта информация должна быть включена в документацию базового объекта. Если вы абсолютно должны иметь код, выполняемый до или после кода дочернего класса, чем вы можете сделать следующее:

1) Создайте не виртуальную функцию в базовом классе. Позвольте называть его MyFunction

2) Создайте защищенную виртуальную функцию в базовом классе. Позвольте называть его _MyFunction

3) Получают классы, расширяющие метод _MyFunction.

4) Попросите MyFunction вызвать _MyFunction и запустите код, который должен выполнить до или после вызова.

Этот метод является уродливым и потребует большого количества дополнительного кода, поэтому я рекомендую просто поместить уведомление в документацию.

Ответ 4

Требования базового класса должны быть задокументированы разработчиком библиотеки. Эта проблема является причиной того, что некоторые библиотеки содержат в основном закрытые классы.