代码之家  ›  专栏  ›  技术社区  ›  Game_Overture

在派生类C中引发基类事件#

  •  8
  • Game_Overture  · 技术社区  · 15 年前

    我有一个基类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);
            }
        }
    

    当然,这个示例可以编译并运行,但是当我将“shapechanged”替换为“move”(从表单派生而来的事件)时,它会错误地说如果没有+=或-=我就不能在右侧移动。我还删除了shapeEventargs通用标记。

    有没有人煽动这件事不起作用?类中声明的事件与继承的事件有什么区别?

    4 回复  |  直到 15 年前
        1
  •  12
  •   vgru    15 年前

    不能直接激发基类事件。这就是为什么你必须 OnShapeChanged 方法 protected 而不是 private .

    使用 base.OnMove() 相反。

        2
  •  4
  •   Charlie    15 年前

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

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

    因此,不能将移动事件视为字段的原因是它是在不同类型(在本例中是超类)中定义的。我同意@womp的推测,即设计师做出这一选择是为了防止意外的胡闹。允许不相关的类型(不是从声明事件的类型派生的类型)执行此操作显然很糟糕,但即使对于派生类型,也可能不需要这样做。它们可能必须包含语法才能进行事件声明。 private protected 关于字段样式的使用,我想他们选择了完全不允许。

        3
  •  3
  •   womp    15 年前

    区别在于范围。在类内部,您可以控制如何处理事件委托,但是,类不能控制基类正在做什么。它可能会在幕后对事件及其处理程序进行一些疯狂的处理。如果只是“重新分配”移动事件,则会清除该事件的多播委派列表。

    我猜他们对此设置了编译器限制,因为这是一个非常不安全的实践,并且本质上会给任何子类破坏其父级事件模型的能力。

        4
  •  1
  •   David Pope    15 年前

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

    如果您确实需要在派生类中进行某种处理(也许您需要处理您的集合类?),您将重写虚拟的onxxx调用,并在调用base.onxxx()之前完成一些操作。在msdn文章中,circle类与dockedtoolWindow类相对应。同样的模式应该对派生类可用。