C#中事件处理的首选方法是什么?

时间:2009-02-11 16:13:00

标签: c# winforms event-handling

在.NET中处理事件的首选/推荐方式是:

this.Load += new EventHandler(Form1_Load);
private void Form1_Load(object sender, EventArgs e)
{ }

protected override void OnLoad(EventArgs e)
{
    base.OnLoad(e);
}

每种方法的优点/缺点是什么?多年来我一直使用这两种方法,并且通常更倾向于第一种方法,因为这是Visual Studio自动创建的用于处理事件的方法。对于我缺少的第二种方法有什么好处吗?

5 个答案:

答案 0 :(得分:8)

第一种方式是微软建议的。模式是:

  1. 某些代码想要举起一个事件,调用OnXxx
  2. OnXxx调用代理
  3. 有线事件处理程序称为
  4. 如果您执行第二个模型,则可能会忘记base.OnXxx调用并破坏所有内容。选项2的好处在于您可以决定是在所有其他事件处理程序之前还是之后调用。如果将代码放在base.OnXxx之前,则会在事件发生之前执行。当然,第一个模型总是可以使用,第二个模型只有在你提升事件的类的子类时才会使用。

答案 1 :(得分:5)

这完全取决于您想要捕捉事件的位置以及原因。

第一种方法(连线)适用于您希望其他类处理事件的时间。出于多种原因,您可能需要这样做;另一个类可以访问执行某些复杂逻辑或其他任何操作的服务。关键是当您希望单独的观察者响应事件时,您使用第一种方法。

第二种方法(覆盖)适用于您希望表单响应的原因,因为它可以;因为它的责任是本地的。

答案 2 :(得分:1)

虽然不是原来的问题,但我想指出:

this.Load += new EventHandler(Form1_Load);

可以写成:

this.Load += Form1_Load;

推断出代表结构。

答案 3 :(得分:0)

没有硬&快速统治,但两种方法都有问题。您可以选择一个可以轻松避免的。

<强>代表

许多开发人员将+ =代码放在可以重复调用的地方。至少很多新手都这样做。因此,所有者控件维护的委托列表中将有'n'个条目,并且所有条目都被调用。要避免的简单方法是将+ =调用放在构造函数类中,只调用一次。

OnXXXX

风险在于忘记调用base.XXX方法。这是一个常见的错误来源,如果你错过调用基类版本,大多数Windows程序员都会意识到这些问题 - 这特别适用于Windows消息(paint等)。

答案 4 :(得分:-1)

重写的方法是首选方法,因为它将由CLR虚拟地调用多态

[编辑]这就是我相信被覆盖的方法更可取的原因:

这是一个简单的例子:

class Foo
{
    public event EventHandler Changed = delegate { };

    protected virtual void OnChanged()
    {
        this.Changed(this, EventArgs.Empty);
    }
}

class Bar : Foo
{
    public Bar()
    {
        this.Changed += new EventHandler(this.Bar_Changed);
    }

    void Bar_Changed(Object sender, EventArgs e) { }
}

class Baz : Foo
{
    protected override void OnChanged() 
    { 
        base.OnChanged();
    }
}

现在我相信Baz是更好的实现,这就是原因。 Bar必须执行以下IL说明来连接事件:

    L_000a: ldftn instance void Bar::Bar_Changed(object, class [mscorlib]System.EventArgs)
    L_0010: newobj instance void [mscorlib]System.EventHandler::.ctor(object, native int)
    L_0015: call instance void Foo::add_Changed(class [mscorlib]System.EventHandler)

我们必须创建一个处理方法的委托,一个EventHandler的实例,然后在基类中的事件上调用add_Changed方法。虽然这些不是性能杀手,但Baz无需使用以前的代码。由于对OnChanged的任何调用都是虚拟的,唯一的性能损失将是CLR找到在继承链中调用的正确实例方法。