Действие <T> против делегирования
Я видел разработчиков, использующих приведенные ниже коды, в качестве альтернативы. Какая разница между ними и какие из них идут по стандарту? Являются ли они такими же, как Action
и Func<T>
также является делегатом:
public event Action<EmployeeEventAgs> OnLeave;
public void Leave()
{
OnLeave(new EmployeeEventAgs(this.ID));
}
VS
public delegate void GoOnLeave(EmployeeEventAgs e);
public event GoOnLeave OnLeave;
public void Leave()
{
OnLeave(new EmployeeEventAgs(this.ID));
}
Ответы
Ответ 1
Fwiw, ни один пример не использует стандартные соглашения .NET. Генератор EventHandler<T>
должен объявить событие:
public event EventHandler<EmployeeEventArgs> Leave;
Префикс "On" должен быть зарезервирован для защищенного метода, который вызывает событие:
protected virtual void OnLeave(EmployeeEventArgs e) {
var handler = Leave;
if (handler != null) handler(this, e);
}
Вам не обязательно это делать, но кто-то мгновенно распознает шаблон, понимает ваш код и знает, как его использовать и настраивать.
И это имеет большое преимущество в том, что вы не должны выбирать между пользовательским объявлением делегата и Action<>
, EventHandler<>
- лучший способ. Что отвечает на ваш вопрос.
Ответ 2
Action<T>
точно такой же, как delegate void ... (T t)
Func<T>
точно совпадает с delegate T ... ()
Ответ 3
Следующие две строки кода почти эквивалентны:
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
. Событие, объявленное явно как таковое с помощью ключевого слова event
, больше не является полем класса. Вместо этого он становится событием. Свойства события аналогичны регулярным свойствам, за исключением того, что у них нет аксессуаров get
или set
. Компилятор позволяет использовать их только в левой части назначений +=
и -=
(добавление или удаление обработчика событий). Невозможно перезаписать уже назначенные обработчики событий или вызвать событие вне класса, объявляющего его.
Если в обоих примерах отсутствует ключевое слово event, вы можете выполнить следующие операции без ошибок или предупреждений:
obj.Leave = LeaveHandler;
который будет удалить любые зарегистрированные обработчики и заменить их на LeaveHandler
.
Кроме того, вы также можете выполнить этот вызов:
obj.Leave(new EmployeeEventAgs());
Два примера выше рассматриваются как анти-шаблон, если вы собираетесь создать событие. Событие должно быть вызвано только объектом-владельцем и не должно допускать бесстрастного удаления подписчиков. Ключевое слово event
- это программная конструкция .NET, которая помогает вам правильно использовать события.
Учитывая вышеизложенное, я считаю, что многие придерживаются подхода EventHandler
, потому что вряд ли он использует EventHandler
без ключевого слова event
. Действия имеют более широкий спектр использования, они не выглядят естественно при использовании в качестве событий. Последнее, конечно, личное мнение, так как подход обработчика событий, вероятно, слишком сильно изменился в моих методах кодирования. Тем не менее, если действия используются правильно, это не преступление, чтобы использовать их для событий.
Ответ 4
Действие - это всего лишь ярлык для полного объявления делегата.
public delegate void Action<T>(T obj)
http://msdn.microsoft.com/en-us/library/018hxwa8.aspx
Какой из них будет зависеть от стандартов/стиля кодирования вашей организации.
Ответ 5
Да, Action и Func - это просто удобные делегаты, которые были определены в 3.5 clr.
Действие, Func и lambdas - всего лишь синтаксический сахар и удобство для использования делегатов.
В них нет ничего волшебного. Несколько человек написали простые 2.0 аддон-библиотеки, чтобы добавить эту функциональность в код 2.0.
Ответ 6
Возможно, вы захотите посмотреть здесь, что лучшее, что генерирует компилятор для Action, - лучшее описание. Там нет функциональной разницы в том, что вы написали, просто более короткий, более удобный синтаксис.
Ответ 7
В общем, они эквивалентны. Но в контексте использования делегата для типа события соглашение должно использовать 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));
}
}
Ответ 8
Вы могли бы написать эти общие делегаты Action и Func самостоятельно, но поскольку они в целом полезны, они написали их для вас и застряли в библиотеках .Net.