Действие<T> против делегата
Я видел разработчиков, использующих приведенные ниже коды совершенно альтернативно. В чем точная разница между ними, и какие идут по стандарту? Они такие же, как Action
а также Func<T>
также является делегатом:
public event Action<EmployeeEventAgs> OnLeave;
public void Leave()
{
OnLeave(new EmployeeEventAgs(this.ID));
}
В.С.
public delegate void GoOnLeave(EmployeeEventAgs e);
public event GoOnLeave OnLeave;
public void Leave()
{
OnLeave(new EmployeeEventAgs(this.ID));
}
8 ответов
Между прочим, ни один из примеров не использует стандартные соглашения.NET. EventHandler<T>
generic должен объявить событие:
public event EventHandler<EmployeeEventArgs> Leave;
Префикс "Вкл" должен быть зарезервирован для защищенного метода, который вызывает событие:
protected virtual void OnLeave(EmployeeEventArgs e) {
var handler = Leave;
if (handler != null) handler(this, e);
}
Вам не нужно делать это таким образом, но кто-то мгновенно распознает шаблон, поймет ваш код и знает, как его использовать и настраивать.
И у него есть большое преимущество: он не вынужден выбирать между пользовательским объявлением делегата и Action<>
, EventHandler<>
это лучший способ. Который отвечает на ваш вопрос.
Следующие две строки кода почти эквивалентны:
public event Action<EmployeeEventAgs> Leave;
по сравнению с:
public event EventHandler<EmployeeEventAgs> Leave;
Разница заключается в сигнатуре метода обработчика событий. Если вы используете первый подход с действием, вы можете иметь:
public void LeaveHandler(EmployeeEventAgs e) { ... }
и тогда это:
obj.Leave += LeaveHandler;
При втором подходе подпись LeaveHandler
должен быть другим:
public void LeaveHandler(object sender, EmployeeEventAgs e) { ... }
Очень важно отметить, что в обоих случаях event
Ключевое слово используется для объявления участника события. Элемент события, объявленный таким образом, не является просто полем класса, несмотря на то, что выглядит так, как если бы он был. Вместо этого компилятор создает его как свойство события 1. Свойства события похожи на обычные свойства, за исключением того, что они не имеют get
или же set
аксессоры. Компилятор позволяет использовать их только в левой части +=
а также -=
назначения (добавление или удаление обработчика событий). Нет способа перезаписать уже назначенные обработчики событий или вызвать событие вне класса, который его объявляет.
Если ключевое слово события отсутствует в обоих примерах, вы можете выполнить следующие операции без ошибок или предупреждений:
obj.Leave = LeaveHandler;
который удалит все зарегистрированные обработчики и заменит их LeaveHandler
,
Кроме того, вы также можете выполнить этот вызов:
obj.Leave(new EmployeeEventAgs());
Вышеуказанные две ситуации считаются антишаблоном, если вы собираетесь создать событие. Событие должно вызываться только объектом-владельцем и не должно допускать неразличимого удаления подписчиков. event
Ключевое слово - это программная конструкция.NET, которая помогает вам правильно использовать события.
Имея в виду вышеизложенное, я считаю, что многие люди придерживаются EventHandler
подход, потому что это вряд ли использовать EventHandler
без event
ключевое слово. Действия имеют более широкую область применения, они не выглядят так естественно, когда используются как события. Последнее, конечно, личное мнение, так как подход к обработчикам событий, вероятно, стал слишком жестким в моей собственной практике кодирования. Тем не менее, если действия используются должным образом, использование их для событий не является преступлением.
1 Свойство события - это то, что компилятор автоматически генерирует при просмотре кода, подобного этому:
event EventHandler SomeEvent
Это становится примерно таким же кодом, как следующий:
private EventHandler _someEvent; // notice the lack of the event keyword!
public event EventHandler SomeEvent
{
add { _someEvent += value; }
remove { _someEvent -= value; }
}
Вызовы событий, которые мы пишем так:
this.SomeEvent(sender, args);
превращаются в это:
this._someEvent(sender, args);
Action<T>
точно так же, как delegate void ... (T t)
Func<T>
точно так же, как delegate T ... ()
Действие - это просто ярлык для полной декларации делегата.
public delegate void Action<T>(T obj)
http://msdn.microsoft.com/en-us/library/018hxwa8.aspx
Какой из них использовать, зависит от стандартов / стиля кодирования вашей организации.
Да, Action и Func являются просто вспомогательными делегатами, которые были определены в 3.5 clr.
Action, Func и lambdas - это всего лишь синтаксический сахар и удобство использования делегатов.
В них нет ничего волшебного. Несколько человек написали простые библиотеки аддонов 2.0, чтобы добавить эту функциональность в код 2.0.
Вы можете посмотреть здесь, чтобы увидеть, что на самом деле генерирует компилятор для Action. Там нет функциональной разницы в том, что вы написали, просто более короткий, более удобный синтаксис.
В целом они эквивалентны. Но в контексте использования делегата для типа события соглашается использовать EventHandler (где T наследует EventArgs):
public event EventHandler<EmployeeEventArgs> Left;
public void Leave()
{
OnLeft(this.ID);
}
protected virtual void OnLeft(int id)
{
if (Left != null) {
Left(new EmployeeEventArgs(id));
}
}
Вы могли бы написать эти обобщенные делегаты Action и Func самостоятельно, но, поскольку они, как правило, полезны, они написали их для вас и поместили в библиотеки.Net.