Почему события обычно используют EventHandler, даже если аргументы не нужно передавать?

Общепринятая практика в С# при создании события, чтобы определить его следующим образом: из примера в .NET Framework Guidelines:

public class CustomEventArgs : EventArgs
{
    public CustomEventArgs(string s)
    {
        msg = s;
    }
    private string msg;
    public string Message
    {
        get { return msg; }
    } 
}

...

public delegate void CustomEventHandler(object sender, CustomEventArgs a);

Часто я создаю события, которые вообще не нуждаются в каких-либо аргументах. Обычно я реализую это просто используя Action для типа обработчика событий.

public event Action LogonScreenExited;

Мне было интересно, есть ли какая-то причина, по которой человек хотел бы следовать "традиционному" образцу. Возможно, подобные события указывают на недостаток дизайна? Однако мои аргументы в пользу использования Action: YAGNI, зачем внедрять что-то (и даже показывать намерение), когда оно не используется?

Ответы

Ответ 1

Это не требование, просто руководство по проектированию.

Вам нужно иметь в виду, что вы не можете предсказать, как клиентский код будет использовать событие, и вы не можете предсказать будущее. Аргумент отправителя полезен для клиентского программиста, он позволяет использовать один метод обработчика событий, который обрабатывает события из нескольких источников событий. Получение из EventArgs полезно, поскольку оно позволяет вам реорганизовать событие, получая исходный базовый класс и добавляя дополнительные аргументы, не нарушая код клиента. Вы можете игнорировать преимущества этого подхода.

Ответ 2

Поскольку вы можете написать общий обработчик событий и использовать его для разных событий (например, для ведения журнала), используя контравариантность в делегаты.

Вот пример из msdn:

// Event hander that accepts a parameter of the EventArgs type. 
private void MultiHandler(object sender, System.EventArgs e)
{
    label1.Text = System.DateTime.Now.ToString();
}

public Form1()
{
    InitializeComponent();

    // You can use a method that has an EventArgs parameter, 
    // although the event expects the KeyEventArgs parameter. 
    this.button1.KeyDown += this.MultiHandler;

    // You can use the same method  
    // for an event that expects the MouseEventArgs parameter. 
    this.button1.MouseClick += this.MultiHandler;

}

Кроме этого, это рекомендуется только руководству по дизайну. После этого ваш код поддерживается и совместим с остальной частью .NET, помогая многим, кто будет использовать ваши классы.

Ответ 3

Вы не должны полагаться на классы, у которых у вас нет доступа к изменению их кодов. Передача дополнительного события arge, который создается из вашего собственного класса EventArgs, позволит вам передать дополнительные аргументы в будущем.

Также ваш код будет поддерживать класс EventHandler<T>, его T должен быть получен из класса EventArgs.