我可以依赖基类的事件执行顺序来避免不必要的虚拟成员吗?

时间:2015-03-29 13:06:22

标签: c# event-handling derived-class

有时我希望我的派生类对某些基类事件做出反应,并在任何其他订阅通知之前更改状态。

我是否需要为每个事件复制protected virtual void HandleXBeforeOthers(...),还是可以依赖这样的事件执行顺序?

public class BaseClass
{
    public event X EventA;
    void RaiseA(...)
    {
        if (EventA != null) EventA(this, ...);
    }

    ...
}

public class Derived : BaseClass
{
    public Derived()
    {
        EventA += ...
    }
}

" protected virtual"方法是:

public class BaseClass
{
    public event X EventA;
    void RaiseA(...)
    {
        HandleEventABeforeOthersCan(...);
        if (EventA != null) EventA(this, ...);
    }

    protected virtual void HandleEventABeforeOthersCan(...)
    {
        ...
    }

    ...
}

public class Derived : BaseClass
{
    protected override void HandleEventABeforeOthersCan(...)
    {
        ...
    }
}

1 个答案:

答案 0 :(得分:0)

答案取决于你想要什么样的保证。

构造函数在字段初始化程序之后执行,基类构造函数在派生类构造函数之前执行。因此,就像您自己的Derived类在其构造函数中为事件添加订阅者一样,在您的之前也可以完成基类。

更糟糕的是,虽然它肯定不赞成,但没有什么可以阻止基类构造函数将this传递给其他代码,在那里它将有机会订阅Derived课前的事件。

最后,只有实现事件的类才能完全控制事件处理程序的实际执行顺序。 通常,它只会调用代表事件的委托实例,该事件将按照订阅的顺序执行每个处理程序。但是,没有什么可以阻止事件的实现者以其他方式维护和使用事件订阅。

E.g。它可以显式实现事件,并在eventField = value + eventField;方法中执行add之类的操作(在订阅时撤消订阅),或者在引发事件时,显式枚举事件的调用列表'委托对象并以相反的顺序调用处理程序。

当然,所有这些场景都应该非常罕见,尤其是最后一场(其中真的很奇怪)。偏离正常事件实现的代码是非常罕见的。但你可以保证代码不是那样的吗?并非没有编写代码的人的承诺(即使在那里,人们也是错误的,可能会忘记或意外地违背他们的承诺)。

因此,如果你想要一个接近铁壳的保证,你的代码将在任何其他代码之前执行,你需要创建自己的类sealed(所以没有其他人可以覆盖事件提升方法),并在通过覆盖实际引发事件的虚方法调用方法的基类实现之前进行处理。

即使在那里,你仍然依赖于隐含的承诺,即事件不会通过任何其他机制被提出。但这就像你将要获得的保证一样好。