Убедитесь, что базовый метод вызывается в С#
Можно ли каким-то образом заставить производный класс всегда вызывать переопределенную базу методов?
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
}
Я искал и нашел предложение использовать не виртуальное обновление(), а также защищенный виртуальный UpdateEx(). Это просто не очень удобно, нет ли лучшего способа?
Надеюсь, у вас возник вопрос, и я сожалею о любом плохом английском.
Ответы
Ответ 1
Используйте шаблон шаблона - не переопределяйте базовый метод, который должен выполнить некоторую работу, переопределить один конкретный бит, который может либо быть абстрактным или нет-op в базовом классе. (Решение о том, делать ли это не-op или абстрактным, обычно довольно очевидно - действительно ли базовый класс имеет смысл сам по себе, как конкретный класс?)
Похоже, что это в основном шаблон, который вы нашли с помощью UpdateEx
- хотя обычно это UpdateImpl
или что-то подобное в моем опыте. С моей точки зрения, нет ничего плохого в качестве шаблона - он избегает любой идеи заставить все производные классы написать один и тот же код для вызова базового метода.
Ответ 2
Я думаю, что предложение, которое вы нашли, хорошо.
Единственный метод базового класса, который нельзя избежать вызова из подкласса в конструкторе базового класса.
Ответ 3
Я думаю, что наличие не виртуального базового элемента, который вызывает виртуальный "крючок", который может быть расширен, является наиболее распространенным решением для такого рода проблем.
В зависимости от вашего варианта использования вы можете вместо этого использовать event
, но обычный шаблон для реализации события должен иметь виртуальный OnEvent
метод, который подклассы могут переопределять вместо добавления обработчика события, поэтому в ваш пример дела сводится к тому же.
Ответ 4
Мне потребовалось немного времени, чтобы посмотреть, как выглядят Update и UpdateEx. Вот пример кода, который может помочь другим.
public class BaseClass
{
// This is the Update that class instances will use, it 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 будет использовать реализацию BaseClass Update() вместе с тем, однако ConcreteClass расширяет его с помощью UpdateEx().