Метод, который принимает как EventHandler, так и EventHandler

#c# #generics

#c# #обобщения

Вопрос:

Предполагая, что у вас есть такой метод, как этот

 private void FireEvent<T>(EventHandler<T> eventHandler, T eventArgs, string name)
{
    var handler = eventHandler;
    if (handler != null)
    {
        Console.WriteLine(String.Format("Sending event {0}", name));
        handler(this, eventArgs);
    }
    else
    {
        throw new UnconnectedEventException(name);
    }
}
 

Можно ли переписать / перегрузить / расширить этот метод, чтобы он принимал оба EventHandler<T> and EventHandler ( eventArgs например, может быть EventArgs.empty в последнем случае)?

Текущим решением является этот дополнительный метод:

 private void FireEvent(EventHandler eventHandler, string name)
{
    var handler = eventHandler;
    if (handler != null)
    {
        Console.WriteLine(String.Format("Sending event {0}", name));
        handler(this, EventArgs.Empty);
    }
    else
    {
        throw new UnconnectedEventException(name);
    }
}
 

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

Примечание: Во втором примере срабатывает an EventHandler , а не an EventHandler<EventArgs> . Эти два типа не могут быть преобразованы друг в друга, поскольку они являются несвязанными делегатами.

Комментарии:

1. можете ли вы просто вызвать fireEvent<object>() ?? Достаточно просто написать функцию-оболочку без универсального аргумента <T> и просто вызвать ваш универсальный метод, используя только object и EventArgs.Empty .

2. Вы пробовали просто добавить метод с требуемой подписью? Если это так, пожалуйста, опубликуйте полученные ошибки (если таковые имеются).

3. Делегаты не имеют наследования, поэтому EventHandler<T> и EventHandler являются принципиально разными типами, которые нельзя обработать одним методом. Но по той же причине нет проблем с FireEvent(EventHandler eventHandler, EventArgs eventArgs string name) перегрузкой. Если вы действительно считаете, что стоит выделить логику, вы можете извлечь handler(this, eventArgs) вызов как an Action , но это приведет к потере эффективности.

4. Поскольку тип eventArgs аргумента (the T ) будет EventArgs , объявите обработчик события как EventHandler<EventArgs> . Я также поддерживаю предложение просто использовать отдельный метод. Только не пытайтесь использовать один метод для выполнения двух отдельных действий только потому, что они кажутся похожими.

Ответ №1:

Я бы сказал, что самое короткое правильное решение, которое не копирует код или игнорирует EventArgs :

 private void FireEvent<T>(EventHandler<T> eventHandler, T eventArgs, string name)
{
    if (eventHandler == null) throw new UnconnectedEventException(name);
    Console.WriteLine(String.Format("Sending event {0}", name));
    eventHandler(this, eventArgs);
}

private void FireEvent(EventHandler eventHandler, EventArgs eventArgs, string name) =>
    FireEvent(eventHandler == null ? null : new EventHandler<EventArgs>(eventHandler), eventArgs, name);
 

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