在派生类中提升基类事件C#

时间:2009-04-23 01:55:28

标签: c# events base-class

我有一个基类DockedToolWindow:Form,以及从DockedToolWindow派生的许多类。我有一个容器类,用于保存和分配事件到DockedToolWindow对象,但是我想调用子类中的事件。

我实际上有一个关于如何实现MSDN site告诉我要做的事情的问题。以下这节给我的问题是:

    // The event. Note that by using the generic EventHandler<T> event type
    // we do not need to declare a separate delegate type.
    public event EventHandler<ShapeEventArgs> ShapeChanged;

    public abstract void Draw();

    //The event-invoking method that derived classes can override.
    protected virtual void OnShapeChanged(ShapeEventArgs e)
    {
        // Make a temporary copy of the event to avoid possibility of
        // a race condition if the last subscriber unsubscribes
        // immediately after the null check and before the event is raised.
        EventHandler<ShapeEventArgs> handler = ShapeChanged;
        if (handler != null)
        {
            handler(this, e);
        }
    }

当然这个例子编译并且有效,但是当我用“Move”(我从Form派生获得的事件)替换“ShapeChanged”时,它错误地说我没有+ =或 - =而没有移动右侧。我还删除了ShapeEventArgs通用标记。

任何煽动为什么这不起作用?在类中声明的事件与继承的事件之间有什么区别?

4 个答案:

答案 0 :(得分:12)

您无法直接触发基类事件。这正是您必须使用OnShapeChanged方法protected而不是private的原因。

改为使用base.OnMove()

答案 1 :(得分:4)

从C#语言规范,第10.7节(增加重点):

  

在包含事件声明的类或结构的程序文本中,可以使用某些事件,如字段。要以这种方式使用,事件不能是抽象的或外部的,并且不能明确包含事件访问器声明。这样的事件可以在允许字段的任何上下文中使用。该字段包含一个委托(第15节),该委托引用已添加到事件的事件处理程序列表。如果未添加事件处理程序,则该字段包含null。

因此,您不能像处理字段一样处理Move事件的原因是它以不同的类型(在本例中为您的超类)定义。我同意@womp的猜测,即设计师做出了这个选择,以防止对事件进行无意识的捣蛋。允许不相关的类型(不是从声明事件的类型派生的类型)执行此操作似乎显然很糟糕,但即使对于派生类型,也可能不合适。他们可能必须包含语法以允许事件声明{field>} privateprotected关于字段式使用,所以我猜他们选择完全禁止它。

答案 2 :(得分:3)

区别在于范围。在您的类中,您可以控制如何处理事件委托,但是,您的类无法控制基类正在执行的操作。它可能会对事件及其处理程序做一些疯狂的幕后操作。如果您只是“重新分配”Move事件,那么您将消除该事件的多播委托列表。

我猜他们对此进行了编译限制,因为它是一种非常不安全的做法,并且基本上会让任​​何后代类能够销毁其父级的事件模型。

答案 3 :(得分:1)

您只需要在定义事件本身的类中发布的代码。所有派生类应该直接调用OnShapeChanged()或OnMove()而不需要复制等,因此您不应该在类中编写该代码(因为Move事件在基础中定义)。

如果你确实需要在派生类中进行某种处理(也许你需要摆弄你的集合类?),你可以覆盖虚拟的OnXXX调用并在调用base.OnXXX()之前进行处理。在MSDN文章中,Circle类对应于DockedToolWindow类。您的派生类应该可以使用相同的模式。