Автоматически создавать пустые обработчики событий C #

Невозможно запустить событие на C #, на котором нет обработчиков. Поэтому перед каждым вызовом необходимо проверить, является ли событие нулевым.

if ( MyEvent != null ) { MyEvent( param1, param2 ); } 

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

 MyEvent( param1, param2 ); 

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

 void Initialize() { MyEvent += new MyEvent( (p1,p2) => { } ); } 

Есть ли способ генерировать пустые обработчики для всех событий данного classа, автоматически используя reflection и некоторую магию CLR?

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

 public delegate void MyClickHandler(object sender, string myValue); public event MyClickHandler Click = delegate {}; // add empty delegate! //Let you do this: public void DoSomething() { Click(this, "foo"); } //Instead of this: public void DoSomething() { if (Click != null) // Unnecessary! Click(this, "foo"); } 

* Если кто-либо знает происхождение этой техники, отправьте ее в комментариях. Я действительно верю в то, что источник получает должный кредит.

( Изменить: я получил это из этого сообщения « Скрытые возможности C #?» )

Обозначение:

 if ( MyEvent != null ) { MyEvent( param1, param2 ); } 

не является streamобезопасным. Вы должны сделать это так:

 EventHandler handler = this.MyEvent; if ( null != handler ) { handler( param1, param2 ); } 

Я понимаю, что это беспокоит, поэтому вы можете использовать вспомогательный метод:

 static void RaiseEvent( EventHandler handler, object sender, EventArgs e ) { if ( null != handler ) { handler( sender, e ); } } 

а затем позвоните:

 RaiseEvent( MyEvent, param1, param2 ); 

Если вы используете C # 3.0, вы можете объявить вспомогательный метод как метод расширения:

 static void Raise( this EventHandler handler, object sender, EventArgs e ) { if ( null != handler ) { handler( sender, e ); } } 

а затем позвоните:

 MyEvent.Raise( param1, param2 ); 

Также вы можете создать следующие методы расширения / помощника для других обработчиков событий. Например:

 static void Raise( this EventHandler handler, object sender, TEventArgs e ) where TEventArgs : EventArgs { if ( null != handler ) { handler( sender, e ); } } 

Вы можете написать так:

 MyEvent += delegate { }; 

Я не уверен, что вы хотите сделать правильно.

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

 public static class EventHandlerExtensions { public static void Raise(this EventHandler handler, object sender, T args) where T : EventArgs { if (handler != null) handler(sender, args); } } 

В C # 6.0 нет необходимости переходить к любой из этих длин, чтобы выполнить нулевую проверку, благодаря условному нулевому оператору ?.

Документы объясняют, что вызов MyEvent?.Invoke(...) копирует событие во временную переменную, выполняет нулевую проверку, а если не null, вызывает Invoke на временной копии. Это не обязательно поточно-безопасное во всех смыслах, так как кто-то мог добавить новое событие после копии во временную переменную, которая не была бы вызвана. Это гарантирует, что вы не будете вызывать Invoke на null.

Вкратце:

 public delegate void MyClickHandler(object sender, string myValue); public event MyClickHandler Click; public void DoSomething() { Click?.Invoke(this, "foo"); } 

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

В объявлениях событий C #, к сожалению, имеется ряд хорошо известных проблем безопасности и неэффективности. Я разработал ряд методов расширения для делегатов, чтобы безопасно их вызывать, а также для регистрации / отмены регистрации делегатов поточно-безопасным способом .

Ваш старый код:

 if (someDelegate != null) someDelegate(x, y, z); 

Ваш новый код:

 someDelegate.Raise(x, y, z); 

Ваш старый регистрационный код:

 event Action fooEvent; ... lock (someDummyObject) fooEvent += newHandler; 

Ваш новый код:

 Action fooEvent; ... Events.Add(ref fooEvent, newHandler); 

Никакой блокировки не требуется, никакие фиктивные объекты, вставленные компилятором, используемые для блокировки событий.

Вы можете использовать PostSharp для добавления времени для создания этой магии. Это лучший способ.

  • Как подписаться на события другого classа в c #?
  • Получить отредактированный TreeNode от CellEditorListener
  • Как работает stream отправки событий?
  • Должен ли я всегда отключать обработчики событий в методе Dispose?
  • Остановить распространение событий мыши в угловом
  • ga или _gaq.push для отслеживания событий Google Analytics?
  • Использование IDisposable для отмены подписки
  • Проверка на нуль до отправки события ... streamобезопасная?
  • Понимание событий и обработчиков событий в C #
  • Избегайте беды Invoke / BeginInvoke в обработке событий в WinForm для кросс-streamов?
  • Как распознать события касания, используя jQuery в Safari для iPad? Является ли это возможным?
  • Давайте будем гением компьютера.