Распространенным шаблоном является наличие не виртуального метода, который будет выполнять то, что вы хотите, который вызывает виртуальный метод.Подклассы могут переопределить внутренний метод, чтобы изменить функциональность, но открытый метод может быть не виртуальным, всегда вызывая событие первым.
public class Foo
{
public SomeHandler OnBar;
public void Bar()
{
if (OnBar != null)
{
OnBar(this, EventArgs.Empty);
}
BarImpl();
}
protected virtual void BarImpl()
{
}
}