Мой класс с событием:
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. Этот код только будет используемым в этом проекте. Мне нравятся конвенции, но действительно ли я прав, когда я говорю, что в этом примере это не имеет смысла, или я неправильно понял что-то?
Если рассматривать изолированно, да, вы правы: традиционный синтаксис .NET более подробный и менее интуитивно понятный, но есть преимущества:
WindowTitle
, - вам придется изменить подпись каждой отдельной функции, которая присоединяется к этому событию, независимо от того, используют ли они его. В подходе EventArgs
вы добавляете свойство к аргументам и изменяете только функции, которые должны использовать дополнительную информацию. 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);
}
Здесь я хотел бы отметить несколько моментов:
null
и будет генерироваться исключение, если вы попытаетесь вызвать его) if (WindowChanged! = Null) WindowChanged (this, e);
, вы фактически столкнетесь с риском того, что событие WindowChanged
станет null
между время, когда вы его проверяете, и время, когда вы его вызываете.Это не важно в однопоточных сценариях, но это отличная защитная привычка, которую нужно сформировать. Вы можете использовать своего делегата. Никто вас не заставит. Это просто хороший шаблон для событий.
Если вы используете стандартный шаблон Sender-EventArgs, вы сможете использовать тот же обработчик ChangeWindow и для других событий.
Я понимаю вашу путаницу ! У меня было такое же чувство, когда я впервые посмотрел на это.
Важно понимать, что это не дает вам большого преимущества с программной точки зрения, но это соглашение, хорошо известное в структуре. Таким образом, существует множество инструментов, ожидающих подписи void EventName (отправитель объекта, EventArgs e)
. Некоторые контейнеры IoC, например, могут использовать эту сигнатуру для автоматического подключения событий во время строительства.
Вкратце, это выглядит немного странно, но это условность. Придерживайтесь этого, и в конце концов лампочка загорится!