English 中文(简体)
C# 中事件处理的首选方法是什么?
原标题:
  • 时间:2009-02-11 16:13:00
  •  标签:

在.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自动创建的用于处理事件的方式。但是,我是否忽略了第二种方法的任何优点呢?

最佳回答

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

  1. some code wants to raise an event, calls OnXxx
  2. OnXxx makes a call to the delegate
  3. Wired event handlers are called

如果您执行第二个模型,则有可能忘记基本的OnXxx调用并破坏一切。选项2的好处是您可以决定是否在所有其他事件处理程序之前或之后被调用。如果您将代码放在base.OnXxx之前,则在事件执行之前执行它。当然,第一个模型可以总是使用,第二个只能在子类化引发事件的类时使用。

问题回答

这完全取决于你想在哪里捕捉这个事件以及为什么。

第一种方法(wire-up)是当您希望其他类别处理事件时使用的。您可能需要出于许多原因这么做; 其他类别可能可以访问执行某些复杂逻辑的服务或其他内容。重点是,当您希望单独的观察者响应事件时使用第一种方法。

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

尽管不是最初的问题,我想指出:

this.Load += new EventHandler(Form1_Load);

可以写为:

this.Load += Form1_Load;

代理构造已被推断。

没有固定的规则,但两种方法都有陷阱。 选择一种可以轻松避免。

代表们

许多开发人员将+=代码放在可以重复调用的位置。至少许多新手会这样做。因此,所有这些位置都会有n个条目,由所有者控件维护,并且所有这些条目都会被调用。避免的简单方法是将+=调用放在仅调用一次的构造函数类似的位置。

抱歉,这个问题无法被准确地翻译,因为XXXX是一个未知的内容或文字。请提供更多的上下文或信息,让我能够更准确地提供翻译。

风险在于忘记调用基础的XXX方法。这是错误的常见来源,大多数Windows程序员都知道如果错过调用基类版本的问题 - 这对于Windows消息(绘画等)的情况尤其如此。

重写的方法更可取,因为它将被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在继承链中查找正确的实例方法以调用。





相关问题
热门标签