Вызывать события C # с помощью метода расширения - это плохо?
-
04-07-2019 - |
Решение
Он по-прежнему будет работать с событиями, которые имеют явное добавление / удаление - вам просто нужно использовать переменную делегата (или, тем не менее, вы сохранили делегат) вместо имени события.
Однако есть более простой способ сделать его поточно-ориентированным - инициализировать его с помощью неоперативного обработчика:
public event EventHandler SomethingHappened = delegate {};
Производительность при вызове дополнительного делегата будет незначительной, и это, безусловно, облегчит код.
Кстати, в вашем методе расширения вам не нужна дополнительная локальная переменная - вы можете просто сделать:
static public void RaiseEvent(this EventHandler @event, object sender, EventArgs e)
{
if (@event != null)
@event(sender, e);
}
static public void RaiseEvent<T>(this EventHandler<T> @event, object sender, T e)
where T : EventArgs
{
if (@event != null)
@event(sender, e);
}
Лично я бы не использовал ключевое слово в качестве имени параметра, но это на самом деле не меняет вызывающую сторону, так что делайте что хотите:)
РЕДАКТИРОВАТЬ: Что касается "OnXXX" Метод: планируете ли вы получать уроки из? На мой взгляд, большинство классов должны быть запечатаны. Если вы делаете , хотите ли вы, чтобы эти производные классы могли вызывать событие? Если ответ на один из этих вопросов "нет" тогда не беспокойся. Если ответом на оба вопроса является "да" тогда делай :)
Другие советы
Теперь C # 6 здесь, есть более компактный, потокобезопасный способ вызвать событие:
SomethingHappened?.Invoke(this, e);
Invoke ()
вызывается только в том случае, если для события зарегистрированы делегаты (т. е. оно не равно нулю), благодаря условному оператору null, "? ".
Проблема с потоками в " обработчике " код в вопросе, который нужно решить, обойден здесь, потому что, как и в этом коде, SomethingHappened
доступен только один раз, поэтому нет никакой возможности установить нулевое значение между тестом и вызовом.
Этот ответ, возможно, имеет отношение к исходному вопросу, но очень полезен для тех, кто ищет более простой способ вызывать события.
[Вот мысль]
Просто напишите код один раз рекомендованным способом и покончите с этим. Тогда вы не будете путать своих коллег, просматривая код, думая, что вы сделали что-то не так? Р>
[Я прочитал больше постов, пытаясь найти способы обхода обработчика событий, чем когда-либо тратил на написание обработчика событий.]
Меньше кода, больше читабельности. Мне нравится.
Если вы не заинтересованы в производительности, вы можете объявить свое мероприятие следующим образом, чтобы избежать проверки на нуль:
public event EventHandler SomethingHappened = delegate{};
Вы не " гарантируете " безопасность потоков, назначая обработчик локальной переменной. Ваш метод все еще может быть прерван после назначения. Если, например, класс, который прослушивал событие, удаляется во время прерывания, вы вызываете метод в расположенном классе.
Вы спасаете себя от исключений с нулевой ссылкой, но есть более простые способы сделать это, как указали Джон Скит и Кристианлибардо в своих ответах.
Другое дело, что для незапечатанных классов метод OnFoo должен быть виртуальным, что я не считаю возможным с помощью методов расширения.