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

时间:2013-05-28 12:50:08

标签: c# events event-handling

我知道以下两种方法都有效,但我想知道在性能/维护/其他方面是否更好。

简短的方法:

  public event EventHandler MyEvent;

漫长的道路:

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

漫长的方式似乎与封装具有属性的成员类似,这确实是一种很好的做法。但这是否适用于事件处理程序?

3 个答案:

答案 0 :(得分:28)

在这种情况下,"良好实践的论点"有点琐事;第一个是"字段式的事件&#34 ;;你注意到:

  

漫长的方式似乎与使用属性

封装成员类似

但是:这是封装的(在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等)执行此操作,因此它不需要专用的专用同步对象。

答案 1 :(得分:5)

第一种方式与创建名为EventHandler的私有MyEvent完全相同。当它在类中被访问时,在类(myClassInstance.MyEvent += SomeHandler / myClassInstance.MyEvent -= SomeHandlerAdd / Remove之外调用时,会返回事件处理程序(即调用委托没有问题)分别叫。这些方法与你用第二种方式编写的方法相同(除了它们增加了线程安全性)。

那你为什么要在实际不需要的时候编写更多代码?

答案 2 :(得分: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);
        }

    }