Bea*_*ker 12 .net c# resharper events event-handling
我见过的大多数代码都使用以下方式来声明和调用事件触发:
public class MyExample
{
public event Action MyEvent; // could be an event EventHandler<EventArgs>, too
private void OnMyEvent()
{
var handler = this.MyEvent; // copy before access (to aviod race cond.)
if (handler != null)
{
handler();
}
}
public void DoSomeThingsAndFireEvent()
{
// ... doing some things here
OnMyEvent();
}
}
Run Code Online (Sandbox Code Playgroud)
甚至ReSharper也会按照上面提到的方式生成一个调用方法.
为什么不这样做:
public class MyExample
{
public event Action MyEvent = delegate {}; // init here, so it's never null
public void DoSomeThingsAndFireEvent()
{
// ... doing some things here
OnMyEvent(); // save to call directly because this can't be null
}
}
Run Code Online (Sandbox Code Playgroud)
任何人都可以解释为什么不这样做的原因?(亲与利弊)
Eri*_*ert 16
优点和缺点是:
空检查非常便宜; 我们正在谈论十亿分之一秒.在对象的整个生命周期中分配一个委托然后垃圾收集失败可能需要花费几百万分之一秒.另外,你消耗了几十个字节的内存.此外,每次事件触发时,您都会对不执行任何操作的方法进行不必要的调用,从而消耗更多的微秒.如果你是那种关心百万分之一秒和几十个字节的人,那么这可能是一个有意义的差异; 对于绝大多数情况,它不会.
您必须记住始终创建空委托.这真的比记住检查null更容易吗?
这两种模式都不会使事件线程安全.事件处理程序在一个线程上被触发同时在另一个线程上被移除时,两个模式仍然是完全可能的,这意味着它们会竞争.如果您的处理程序删除代码破坏了处理程序所需的状态,那么当另一个线程正在运行处理程序时,一个线程可能正在销毁该状态.不要以为只检查null或分配空处理程序会神奇地消除竞争条件.它只消除导致取消引用null的竞争条件.
它可以仍然为空.考虑:
var x = new MyExample();
x.MyEvent += SomeHandler;
// ... later, when the above code is disposed of
x.MyEvent -= SomeHandler;
Run Code Online (Sandbox Code Playgroud)
编辑:实际上,我把它拿回来.测试过此后,如果您使用匿名委托设置处理程序,则看起来不能清除它,因此您可以保存空检查.
我不确定这是否是可靠的行为,或者只是语言实现的工件......
| 归档时间: |
|
| 查看次数: |
1108 次 |
| 最近记录: |