与继承时订阅事件相反,何时应该重写OnEvent

时间:2020-03-06 14:59:39  来源:igfitidea点击:

以下什么时候应该做?

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

解决方案

覆盖而不是添加委托将使代码更有效,因此通常建议我们始终在可能的情况下执行此操作。有关更多信息,请参见此MSDN文章。这是一个相关的报价:

The protected OnEventName method also
  allows derived classes to override the
  event without attaching a delegate to
  it. A derived class must always call
  the OnEventName method of the base
  class to ensure that registered
  delegates receive the event.

该事件是针对外部订户的。当我们派生某些控件时,请始终重写OnEvent方法,而不是订阅事件。这样,我们可以确定何时调用代码,因为在调用base.OnEvent()时会触发实际事件,并且可以在代码之前,代码之后,代码中间或者不在代码中间调用此事件。全部。然后,我们还可以对事件的返回值(即EventArgs对象中的更改属性)做出反应。

如果我们像Kent Boogaart的注释那样覆盖,则需要谨慎地回调base.OnClick以允许调用事件订阅

继承的类永远不要订阅自己的事件或者基类的事件。

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

例如,我最近推出了一个MRU List类。其中包含许多ToolStripMenuItem控件,我使用了它们的click事件。在点击事件被消耗之后,我随后提出了班级的事件。 (请参见此处的源代码)

订阅事件旨在使控件监视其他控件上的事件。对于监视我们自己的事件,OnClick很好。但是请注意,Control.OnClick会处理触发这些订阅的事件,因此请确保在替代中调用它。

请注意(至少在.NET 2.0中),我在框架中(特别是在DataTable类中)找到了几个地方,只有在处理了相应的Foo事件后才调用OnFoo方法!这违反了框架设计准则,但我们坚持使用它。

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

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