这是不可能的火在没有连接到它的处理程序C#的事件。 所以每次打电话之前,有必要检查该事件是否为空。
if ( MyEvent != null ) {
MyEvent( param1, param2 );
}
我想保持我的代码尽可能干净,摆脱那些null检查。 我不认为这会影响性能非常多,至少不会在我的情况。
MyEvent( param1, param2 );
现在,我可以手动添加一个空行内处理每个事件解决这个问题。 这是很容易出错的,因为我需要记住这样做等。
void Initialize() {
MyEvent += new MyEvent( (p1,p2) => { } );
}
有没有一种方法来生成自动使用反射和一些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 );
}
不是线程安全的。 你应该做的是这样的:
EventHandler handler = this.MyEvent;
if ( null != handler ) { handler( param1, param2 ); }
我明白了,这是很麻烦的事情,所以你可以做helper方法:
static void RaiseEvent( EventHandler handler, object sender, EventArgs e ) {
if ( null != handler ) { handler( sender, e ); }
}
然后调用:
RaiseEvent( MyEvent, param1, param2 );
如果您正在使用C#3.0中,你可以声明helper方法为扩展方法:
static void Raise( this EventHandler handler, object sender, EventArgs e ) {
if ( null != handler ) { handler( sender, e ); }
}
然后调用:
MyEvent.Raise( param1, param2 );
你还可以创建其他的事件处理程序的下一个扩展/辅助方法。 例如:
static void Raise<TEventArgs>( this EventHandler<TEventArgs> handler,
object sender, TEventArgs e ) where TEventArgs : EventArgs
{
if ( null != handler ) { handler( sender, e ); }
}
你并不需要为不同的事件处理程序的几个扩展方法,你只需要一个:
public static class EventHandlerExtensions {
public static void Raise<T>(this EventHandler<T> handler, object sender, T args) where T : EventArgs {
if (handler != null) handler(sender, args);
}
}
在C#6.0没有必要去任何这些长度做的空检查,由于条件空操作?.
该文档说明,调用MyEvent?.Invoke(...)
复制事件给一个临时变量,执行空校验,如果不为空,调用Invoke
的临时副本。 这并不一定是线程安全在任何意义上,有人可以复制到临时变量,它就不叫后增加了一个新的事件。 它保证你不会调用Invoke
虽然对空。
简而言之:
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对建造时间增加这个魔术。 这是最好的方式。