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

C# 在派生类C中引发基类事件#,c#,events,base-class,C#,Events,Base Class,我有一个基类DockedToolWindow:Form,以及许多从DockedToolWindow派生的类。我有一个容器类,它保存事件并将事件分配给DockedToolWindow对象,但是我希望从子类调用事件 实际上,我有一个问题,关于如何实现这是告诉我要做的。下面这一节给了我一个问题: // The event. Note that by using the generic EventHandler<T> event type // we do not need

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

实际上,我有一个问题,关于如何实现这是告诉我要做的。下面这一节给了我一个问题:

    // 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);
        }
    }
//事件。请注意,通过使用泛型EventHandler事件类型
//我们不需要声明单独的委托类型。
公共事件事件处理程序形状已更改;
公开摘要无效抽取();
//派生类可以重写的事件调用方法。
ShapeChanged(ShapeEventArgs e)上受保护的虚拟空间
{
//制作事件的临时副本,以避免
//最后一个订户取消订阅时的竞争条件
//在空检查之后和引发事件之前。
EventHandler=ShapeChanged;
if(处理程序!=null)
{
处理者(本,e);
}
}
当然这个例子可以编译并运行,但是当我用“Move”(我从表单派生的事件)替换“ShapeChanged”时,它会错误地说如果没有+=或-=,我就不能在右侧移动。我还删除了ShapeEventArgs通用标记


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

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

我猜他们对此设置了编译器限制,因为这是一种非常不安全的做法,本质上会让任何子类都有能力破坏其父类的事件模型。

来自C语言规范,第10.7节(重点补充):

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


因此,不能将移动事件视为字段的原因是,它是在不同的类型中定义的(在本例中是您的超类)。我同意@womp的猜测,即设计师做出这一选择是为了防止意外地操纵活动。允许不相关的类型(不是从声明事件的类型派生的类型)这样做显然是不好的,但即使对于派生类型,也可能不可取。他们可能必须包含语法,以允许事件声明在字段样式使用方面成为私有的或受保护的,因此我猜他们选择完全不允许它。

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


如果确实需要在派生类中进行某种处理(可能需要处理集合类?),则可以重写虚拟OnXXX调用,并在调用base.OnXXX()之前进行填充。在MSDN文章中,Circle类对应于DockedToolWindow类。派生类应该可以使用相同的模式。

不能直接触发基类事件。这正是您必须将
OnShapeChanged
方法
设置为protected
而不是
private
的原因


改用。

我知道OnMove()可以解决这个问题,但是当需要时,我怎么不能显式调用OnMove()呢?我不知道框架实际上在哪里调用移动委托,而且可能对我来说是隐藏的。我知道OnMove()可以解决这个问题,但是当需要时,我怎么不能显式调用OnMove()呢?我不知道框架实际上在哪里调用移动委托,而且可能对我隐藏了。OnMove触发移动事件的方式与OnShapeChanged在代码中触发ShapeChanged事件的方式相同。添加触发事件的受保护成员以使其对派生类可见是一种常见的模式。在这种情况下,通常会添加“On”前缀(OnMove、OnClick等),以查看框架实际触发移动事件的位置,请使用Reflector工具()获取Form.OnMove方法的源代码。[注意]Reflector从此成为付费应用程序,因此(如果您想要免费应用程序),您需要签出或其他类似应用程序。来自Telerik的信息是免费的。