Конвенция событий - я не получаю его

Мой класс с событием:

public class WindowModel
{
    public delegate void WindowChangedHandler(object source, WindowTypeEventArgs e);
    public event WindowChangedHandler WindowChanged;  

    public void GotoWindow(WindowType windowType)
    {
        this.currentWindow = windowType;
        this.WindowChanged.Invoke(this, new WindowTypeEventArgs(windowType));
    }
}

Полученный класс событий:

public class WindowTypeEventArgs : EventArgs
{
    public readonly WindowType windowType;

    public WindowTypeEventArgs(WindowType windowType)
    {
        this.windowType = windowType;
    }
}

Некоторый другой класс, которые регистрируют его к событию:

private void SetupEvents()
{
   this.WindowModel.WindowChanged += this.ChangeWindow;
}

private void ChangeWindow(object sender, WindowTypeEventArgs e)
{
   //change window
}

Что я получил от следующего конвенцию .NET? Имело бы больше смысла иметь контракт как это

public delegate void WindowChangedHandler(WindowType windowType);
public event WindowChangedHandler WindowChanged;

Делая его этот путь, я не должен создавать новый класс, и легче понять. Я не кодирую библиотеку .NET. Этот код только будет используемым в этом проекте. Мне нравятся конвенции, но действительно ли я прав, когда я говорю, что в этом примере это не имеет смысла, или я неправильно понял что-то?

6
задан Mads Andersen 19 April 2010 в 17:54
поделиться

3 ответа

Если рассматривать изолированно, да, вы правы: традиционный синтаксис .NET более подробный и менее интуитивно понятный, но есть преимущества:

  • Будущее изменения информации, передаваемой вашим событием, не требуют автоматического изменения каждого потребителя события. Например, если вы хотите добавить к своему событию дополнительную информацию - скажем, строку WindowTitle , - вам придется изменить подпись каждой отдельной функции, которая присоединяется к этому событию, независимо от того, используют ли они его. В подходе EventArgs вы добавляете свойство к аргументам и изменяете только функции, которые должны использовать дополнительную информацию.
  • Начиная с .NET 2.0 представил тип делегата EventHandler , вам больше не нужно определять свои собственные делегаты событий вручную. В вашем примере вы должны ввести свое событие как EventHandler вместо WindowChangedHandler .
  • Подход EventArgs упрощает передачу нескольких типов информации обратно в вызывающую функцию. Если вам нужно было сделать это в вашем альтернативном примере (который передает параметр события напрямую), вы все равно создадите свой собственный класс -tuple для хранения информации.

Влияние первого становится более очевидным, если вы посмотрите на фактический шаблон для событий .NET при создании защищенной виртуальной функции, которая фактически выполняет вызов. Например:

public event EventHandler<WindowTypeEventArgs> WindowChanged;

protected virtual void OnWindowChanged(WindowTypeEventArgs e)
{
    var evt = WindowChanged;

    if(evt != null) evt(this, e);
}

Здесь я хотел бы отметить несколько моментов:

  1. Использование шаблона создания этого метода, вызывающего событие, позволяет избежать проверки на null во всем коде (событие без прикрепленных функций для него будет null и будет генерироваться исключение, если вы попытаетесь вызвать его)
  2. Этот шаблон также позволяет классам, которые унаследованы от вас, управлять порядком вызова, позволяя им выполнять свой код явно либо до или после любых внешних потребителей
  3. Это особенно важно в многопоточных средах. Если вы просто скажете if (WindowChanged! = Null) WindowChanged (this, e); , вы фактически столкнетесь с риском того, что событие WindowChanged станет null между время, когда вы его проверяете, и время, когда вы его вызываете.Это не важно в однопоточных сценариях, но это отличная защитная привычка, которую нужно сформировать.
15
ответ дан 8 December 2019 в 12:18
поделиться

Вы можете использовать своего делегата. Никто вас не заставит. Это просто хороший шаблон для событий.

Если вы используете стандартный шаблон Sender-EventArgs, вы сможете использовать тот же обработчик ChangeWindow и для других событий.

1
ответ дан 8 December 2019 в 12:18
поделиться

Я понимаю вашу путаницу ! У меня было такое же чувство, когда я впервые посмотрел на это.

Важно понимать, что это не дает вам большого преимущества с программной точки зрения, но это соглашение, хорошо известное в структуре. Таким образом, существует множество инструментов, ожидающих подписи void EventName (отправитель объекта, EventArgs e) . Некоторые контейнеры IoC, например, могут использовать эту сигнатуру для автоматического подключения событий во время строительства.

Вкратце, это выглядит немного странно, но это условность. Придерживайтесь этого, и в конце концов лампочка загорится!

3
ответ дан 8 December 2019 в 12:18
поделиться
Другие вопросы по тегам:

Похожие вопросы: