Убедитесь, что базовый метод вызывается в C # - PullRequest
21 голосов
/ 31 мая 2010

Можно ли как-то заставить производный класс всегда вызывать переопределенные методы base?

public class BaseClass
{
    public virtual void Update()
    {
        if(condition)
        {
            throw new Exception("..."); // Prevent derived method to be called
        }
    }
}

А потом в производном классе:

public override void Update()
{
    base.Update(); // Forced call

    // Do any work
}

Я искал и нашел предложение использовать не виртуальное обновление (), а также защищенное виртуальное обновление (). Просто не очень аккуратно, разве нет лучшего способа?

Я надеюсь, что вы получите вопрос, и я прошу прощения за плохой английский.

Ответы [ 4 ]

29 голосов
/ 31 мая 2010

Используйте шаблонный шаблонный метод - не переопределяйте базовый метод, который требует некоторой работы, переопределите один конкретный бит, который может быть либо абстрактным, либо неоперативным в базовом классе. (Решение о том, делать ли это неоперативным или абстрактным, обычно достаточно очевидно - имеет ли базовый класс смысл как отдельный класс?)

Похоже, что это в основном шаблон, который вы нашли с UpdateEx - хотя обычно это UpdateImpl или что-то подобное в моем опыте. На мой взгляд, в этом нет ничего плохого в качестве шаблона - он избегает любой идеи заставить все производные классы писать один и тот же код для вызова базового метода.

2 голосов
/ 08 мая 2015

Мне понадобилось немного времени, чтобы понять, как будут выглядеть Update и UpdateEx. Вот пример кода, который может помочь другим.

public class BaseClass
{
    // This is the Update that class instances will use, it's never overridden by a subclass
    public void Update()
    {
        if(condition);
        // etc... base class code that will always run

        UpdateEx(); // ensure subclass Update() functionality is run
    }

    protected virtual void UpdateEx()
    {
        // does nothing unless sub-class overrides
    }
}

У подкласса никогда не будет никакой реализации для Update (). Он будет использовать UpdateEx () для добавления реализации в Update ();

public class ConcreteClass : BaseClass
{
    protected override void UpdateEx()
    {
        // implementation to be added to the BaseClass Update();
    }
}

Любой экземпляр ConcreteClass будет использовать реализацию Update () BaseClass вместе с тем, однако ConcreteClass расширяет его функцией UpdateEx ().

2 голосов
/ 31 мая 2010

Я думаю, что наличие не виртуального базового члена, который вызывает виртуальный «хук», который можно расширить, является наиболее распространенным решением для такого рода проблем.

В зависимости от вашего варианта использования вы можете вместо этого использовать event, но обычным способом реализации события является наличие виртуального OnEvent метода, который подклассы могут переопределять вместо добавления обработчика события, поэтому в в вашем примере это сводится к одному и тому же.

2 голосов
/ 31 мая 2010

Я думаю, что предложение, которое вы нашли, хорошо.

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

...