在C#中声明事件的最佳实践

13

我知道以下两种方法都可以正常工作,但我想知道哪一种在性能/维护/其他方面更好。

简短的方式:

  public event EventHandler MyEvent;

使用较长的方法:

  private EventHandler _myEvent;
  public event EventHandler MyEvent
  {
     add { _myEvent += value; }
     remove { _myEvent -= value; }
  }

长久以来,似乎将成员封装为属性与事件处理程序的实践相似,这确实是一个好习惯。但这是否适用于事件处理程序?


自动属性为什么是不良实践? - Lews Therin
也许是因为我比较懒,但我总是选择简短的版本 :) - Dimitar Dimitrov
1
我第一次猜想就是,对于大多数情况而言,简短的方式已经足够了。只有当你真正需要时才需要使用冗长的方式,也就是说,当事件被注册或未被注册时,你需要做一些额外的工作。 - MBender
@Lews:我不是指自动属性,而是公共成员。例如:public int Number; 是不好的实践。而 public int Number { get; set; } 则不是。 - Johnny5
1
有时候,为了调试、清除调用列表等操作,实际的委托也是必要的。 - dowhilefor
3个回答

30
在这种情况下,“良好实践”的论点有些棘手;首先是“类似于字段的事件”,你可以注意到:

长方式似乎类似于使用属性封装成员,

但是:不管哪种方式,都已经被封装(在add/remove后面);因此与属性相比,实际上区别在于:
public int Foo {get;set;}

private int foo;
public int Foo {
    get { return foo; }
    set { foo = value; }
}

如果没有实际理由,我会建议你使用第一个 - 它仍然被访问器隐藏。此外,需要注意的是第二个示例不是字段事件(第一个示例)所扩展的内容:编译器在其中加入了线程安全性。因此:我会建议使用第一个示例:

public event EventHandler MyEvent;

请注意,线程安全的“如何”取决于您使用的编译器版本(以及确切的规范)。在最近的 Microsoft C# 编译器中,它使用Interlocked操作(CompareExchange等)来实现这一点,因此不需要专用的私有同步对象。


5
第一种方法与创建名为MyEvent的私有EventHandler完全相同。当其在类内被访问时,将返回事件处理程序(即调用委托没有问题),当在类外部被调用(myClassInstance.MyEvent += SomeHandler/myClassInstance.MyEvent -= SomeHandler)时,分别调用Add/Remove方法。而这些方法与您在第二种方法中编写的方法相同(除了添加线程安全性)。因此,为什么要写更多的代码,当你实际上不需要它呢?

4
实际上,它们并不完全相同;编译器为类似字段的事件示例(第一个示例)包含了线程安全性。 - Marc Gravell

1
为了检查Marc Gravel的意思,我尝试了以下代码:
public event EventHandler MyEventShortWay;

private EventHandler _myEvent;
public event EventHandler MyEventLongWay
{
    add { _myEvent += value; }
    remove { _myEvent -= value; }
}

我对生成的内容感到惊讶(我编辑了反编译变量名):

private EventHandler _myEventShortWay;

public event EventHandler MyEventShortWay
    {
        add
        {
            EventHandler handler2;
            EventHandler myEventShortWay = this._myEventShortWay;
            do
            {
                handler2 = myEventShortWay;
                EventHandler handler3 = (EventHandler)Delegate.Combine(handler2, value);
                myEventShortWay = Interlocked.CompareExchange<EventHandler>(ref this._myEventShortWay, handler3, handler2);
            }
            while (myEventShortWay != handler2);
        }
        remove
        {
            EventHandler handler2;
            EventHandler myEventShortWay = this._myEventShortWay;
            do
            {
                handler2 = myEventShortWay;
                EventHandler handler3 = (EventHandler)Delegate.Remove(handler2, value);
                myEventShortWay = Interlocked.CompareExchange<EventHandler>(ref this._myEventShortWay, handler3, handler2);
            }
            while (myEventShortWay != handler2);
        }
    }

    private EventHandler _myEvent;

    public event EventHandler MyEventLongWay
    {
        add
        {
            this._myEvent = (EventHandler) Delegate.Combine(this._myEvent, value);
        }
        remove
        {
            this._myEvent = (EventHandler)Delegate.Remove(this._myEvent, value);
        }

    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接