Подтвердить что ты не робот

Лучшая практика объявления событий в С#

Я знаю, что работают следующие два метода, но мне интересно, лучше ли с точки зрения производительности/обслуживания/чего-то еще.

Короткий путь:

  public event EventHandler MyEvent;

Длинный путь:

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

Длинный путь похож на инкапсуляцию элементов со свойствами, что действительно является хорошей практикой. Но применимо ли это к обработчикам событий?

4b9b3361

Ответ 1

В этом случае аргумент "хорошей практики" - немного сложнее; первое - "полевое событие"; вы отмечаете:

Длинный путь похож на инкапсуляцию элементов со свойствами,

но: это инкапсулировано (за add/remove) в любом случае; поэтому по сравнению со свойствами это действительно разница между:

public int Foo {get;set;}

и

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

В этом случае я бы сказал: "Используйте первый, если у вас нет фактической причины не делать этого" - он по-прежнему скрыт за аксессуарами. Кроме того, важно отметить, что ваш второй пример не, что расширяет полеподобное событие (первый пример): компилятор добавляет безопасность потока в микс. Итак: я бы сказал, используя первый образец:

public event EventHandler MyEvent;

Обратите внимание, что "как" для безопасности потоков зависит от того, какая версия компилятора (и, действительно, какая спецификация) вы используете. В недавних компиляторах Microsoft С# это выполняется с помощью операций Interlocked (CompareExchange и т.д.), Поэтому для него не требуется выделенный частный объект синхронизации.

Ответ 2

Первый способ делает то же самое с созданием private EventHandler с именем MyEvent. Когда он возвращается в обработчик события класса, возвращается (т.е. Не проблема с вызывающим делегатом), когда он вызывается вне класса (myClassInstance.MyEvent += SomeHandler/myClassInstance.MyEvent -= SomeHandler), методы называются соответственно Add/Remove. И эти методы одинаковы (за исключением того, что они добавляют безопасность потоков), как те, которые вы написали вторым способом.

Итак, почему вы хотите написать больше кода, когда вам это действительно не нужно?

Ответ 3

Чтобы проверить, что означает 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);
        }

    }