何时应覆盖 OnEvent,而不是在继承时订阅事件

本文关键字:继承 事件 OnEvent 覆盖 何时应 | 更新日期: 2023-09-27 17:47:23

什么时候应该执行以下操作?

class Foo : Control
{
    protected override void OnClick(EventArgs e)
    {
        // new code here
    }
}

与此相反?

class Foo : Control
{
    public Foo()
    {
        this.Click += new EventHandler(Clicked);
    }
    private void Clicked(object sender, EventArgs e)
    {
        // code
    }
}

何时应覆盖 OnEvent,而不是在继承时订阅事件

重写而不是附加委托将导致更高效的代码,因此通常建议您尽可能始终执行此操作。有关详细信息,请参阅此 MSDN 文章。以下是相关引述:

受保护的 OnEventName 方法还 允许派生类重写 事件,而不将委托附加到 它。派生类必须始终调用 基的 OnEventName 方法。 类以确保注册 代表们接受活动。

该活动适用于外部订阅者。派生某些控件时,请始终重写 OnEvent 方法,而不是订阅事件。这样,您可以确定何时调用代码,因为实际事件是在调用 base 时触发的。OnEvent(),你可以在代码之前、代码之后、代码中间或根本不调用它。然后,您还可以对事件的返回值(即 EventArgs 对象中更改的属性)做出反应。

请注意

(至少在 .NET 2.0 中),我在框架中发现了一些地方(特别是在 DataTable 类中),其中 OnFoo 方法仅在处理了相应的 Foo 事件时才被调用!这违反了框架设计指南,但我们坚持下去。

我已经通过在类中的某个地方使用虚拟处理程序处理事件来绕过它,例如:

public class MyDataTable : DataTable
{
    public override void EndInit()
    {
        base.EndInit();
        this.TableNewRow += delegate(object sender, DataTableNewRowEventArgs e) { };
    }
    protected override void OnTableNewRow(DataTableNewRowEventArgs e)
    {
        base.OnTableNewRow(e);
        // your code here
    }
}

订阅事件旨在使控件监视不同控件上的事件。 用于监视您自己的事件 OnClick 很好。 但请注意,Control.OnClick 会处理触发这些订阅的事件,因此请务必在覆盖中调用它。

如果你像肯特·布加特(Kent Boogaart)的评论一样覆盖,你需要小心回拨基地。单击以允许调用事件描述

继承

的类永远不应该订阅它自己的事件,或者它是基类的事件。

现在,如果一个类中有另一个不同的类的实例,那么它可以使用该类的事件,并确定它是否应该引发它自己的事件。

例如,我最近推出了一个 MRU 列表类。其中有许多 ToolStripMenuItem 控件,我使用了这些控件的单击事件。使用该点击事件后,我随后引发了班级的事件。(请参阅此处的源代码)

值得注意的是,在某些极端情况下,它仅适用于处理程序,而不适用于 OnEvent 覆盖。一个这样的例子——

为什么在 WPF 中删除 StartupUri 时不应用样式?