9

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

我实际上有一个关于如何实现这个MSDN 网站告诉我要做的事情的问题。下面的这一部分给了我这个问题:

    // 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

4 回答 4

12

您不能直接触发基类事件。这正是您必须制作OnShapeChanged方法protected而不是private.

请改用base.OnMove()

于 2009-04-23T09:36:56.343 回答
4

从 C# 语言规范,第 10.7 节(强调添加):

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

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

于 2009-04-23T02:39:35.113 回答
3

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

我猜他们对此施加了编译器限制,因为这是一种非常不安全的做法,并且本质上会使任何后代类都能够破坏其父类的事件模型。

于 2009-04-23T02:15:19.197 回答
1

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

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

于 2009-04-23T04:06:21.130 回答