Действие <T>против делегата - PullRequest
56 голосов
/ 17 февраля 2010

Я видел разработчиков, использующих приведенные ниже коды совершенно альтернативно.В чем точная разница между ними, и какие идут по стандарту?Они такие же, как 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));
}

Ответы [ 8 ]

51 голосов
/ 17 февраля 2010

Между прочим, ни один из примеров не использует стандартные соглашения .NET.Обобщение EventHandler<T> должно объявлять событие:

public event EventHandler<EmployeeEventArgs> Leave;

Префикс «Вкл» должен быть зарезервирован для защищенного метода, вызывающего событие:

protected virtual void OnLeave(EmployeeEventArgs e) {
    var handler = Leave;
    if (handler != null) handler(this, e);
}

Вы не должны сделать это таким образом, но кто-нибудь мгновенно распознает шаблон, поймет ваш код и знает, как его использовать и настроить.

И у него есть большое преимущество - он не вынужден выбиратьмежду пользовательским объявлением делегата и Action<>, EventHandler<> - лучший способ.Который отвечает на ваш вопрос.

27 голосов
/ 05 апреля 2014

Следующие две строки кода почти эквивалентны:

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 методов доступа. Компилятор позволяет использовать их только в левой части назначений += и -= (добавление или удаление обработчика событий). невозможно переписать уже назначенные обработчики событий или вызвать событие вне класса, который объявляет it.

Если ключевое слово события отсутствует в обоих примерах, вы можете выполнить следующие операции без ошибок или предупреждений:

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);
21 голосов
/ 17 февраля 2010

Action<T> точно так же, как delegate void ... (T t)

Func<T> точно так же, как delegate T ... ()

6 голосов
/ 17 февраля 2010

Действие - это просто ярлык для полного объявления делегата.

public delegate void Action<T>(T obj)

http://msdn.microsoft.com/en-us/library/018hxwa8.aspx

Какой из них использовать, будет зависеть от стандартов / стиля кодирования вашей организации.

4 голосов
/ 17 февраля 2010

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

4 голосов
/ 17 февраля 2010

Да, Action и Func - это просто удобные делегаты, определенные в п. 3.5.

Action, Func и lambdas - это всего лишь синтаксический сахар и удобство использования делегатов.

В них нет ничего волшебного. Несколько человек написали простые библиотеки дополнений 2.0, чтобы добавить эту функциональность в код 2.0.

3 голосов
/ 17 февраля 2010

В целом они эквивалентны. Но в контексте использования делегата для типа события соглашение состоит в том, чтобы использовать 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));
    }
}
0 голосов
/ 17 февраля 2010

Вы могли бы написать эти обобщенные делегаты Action и Func самостоятельно, но, поскольку они, как правило, полезны, они написали их для вас и поместили в библиотеки .Net.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...