在事件声明中添加匿名空委托有缺点吗?
我见过一些关于这个习语的提及(包括on SO):
// Deliberately empty subscriber
public event EventHandler AskQuestion = delegate {};
好处是clear - 它避免了在引发事件之前检查 null 的需要。
但是,我很想知道是否有任何缺点。例如,它是否被广泛使用并且足够透明,不会导致维护麻烦? 空事件订阅者调用是否会对性能造成明显影响?
I have seen a few mentions of this idiom (including on SO):
// Deliberately empty subscriber
public event EventHandler AskQuestion = delegate {};
The upside is clear - it avoids the need to check for null before raising the event.
However, I am keen to understand if there are any downsides. For example, is it something that is in widespread use and is transparent enough that it won't cause a maintenance headache? Is there any appreciable performance hit of the empty event subscriber call?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
为什么不使用扩展方法来缓解这两个问题,而不是引起性能开销:
一次定义后,您不必再次进行空事件检查:
Instead of inducing performance overhead, why not use an extension method to alleviate both problems:
Once defined, you never have to do another null event check again:
对于大量使用事件并且对性能至关重要的系统,您肯定至少考虑不这样做。 使用空委托引发事件的成本大约是首先使用空检查引发事件的成本的两倍。
以下是在我的机器上运行基准测试的一些数据:
这是我用来获取这些数据的代码:
For systems that make heavy use of events and are performance-critical, you will definitely want to at least consider not doing this. The cost for raising an event with an empty delegate is roughly twice that for raising it with a null check first.
Here are some figures running benchmarks on my machine:
And here is the code I used to get these figures:
唯一的缺点是,当您调用额外的空委托时,性能会受到非常轻微的影响。 除此之外,没有维护惩罚或其他缺点。
The only downside is a very slight performance penalty as you are calling extra empty delegate. Other than that there is no maintenance penalty or other drawback.
如果您经常这样做,您可能希望有一个可重复使用的单个静态/共享空委托,只是为了减少委托实例的数量。 请注意,编译器无论如何都会缓存每个事件的此委托(在静态字段中),因此每个事件定义只有一个委托实例,因此这不是一个巨大的节省 - 但也许是值得的。
当然,每个类中的每个实例字段仍将占用相同的空间。
即
除此之外,似乎还不错。
If you are doing it a /lot/, you might want to have a single, static/shared empty delegate that you re-use, simply to reduce the volume of delegate instances. Note that the compiler caches this delegate per event anyway (in a static field), so it is only one delegate instance per event definition, so it isn't a huge saving - but maybe worthwhile.
The per-instance field in each class will still take the same space, of course.
i.e.
Other than that, it seems fine.
除了可能的某些极端情况之外,没有什么有意义的性能损失可讨论。
但请注意,此技巧在 C# 6.0 中变得不太相关,因为该语言提供了一种替代语法来调用可能为 null 的委托:
上面,null 条件运算符
?.
将 null 检查与条件调用结合在一起。There is no meaningful performance penalty to talk about, except, possibly, for some extreme situations.
Note, however, that this trick becomes less relevant in C# 6.0, because the language provides an alternative syntax to calling delegates that may be null:
Above, null conditional operator
?.
combines null checking with a conditional invocation.据我了解,空委托是线程安全的,而空检查则不是。
It is my understanding that the empty delegate is thread safe, whereas the null check is not.
我想说这是一个有点危险的构造,因为它诱惑你做类似的事情:
如果客户端抛出异常,服务器也会随之而来。
那么,也许您会这样做:
但是,如果您有多个订阅者并且其中一个订阅者抛出异常,那么其他订阅者会发生什么情况?
为此,我一直在使用一些静态辅助方法来执行空检查并吞掉订阅者端的任何异常(这来自 idesign)。
I would say it's a bit of a dangerous construct, because it tempts you to do something like :
If the client throws an exception, the server goes with it.
So then, maybe you do:
But, if you have multiple subscribers and one subscriber throws an exception, what happens to the other subscribers?
To that end, I've been using some static helper methods that do the null check and swallows any exception from the subscriber side (this is from idesign).
除了“空委托”方法之外,我们还可以定义一种简单的扩展方法来封装检查事件处理程序是否为 null 的传统方法。 此处和此处。
Instead of "empty delegate" approach one can define a simple extension method to encapsulate the conventional method of checking event handler against null. It is described here and here.
到目前为止,这个问题的答案被遗漏了:避免检查 null 值是危险的。
问题是:您永远不知道谁会以哪种方式使用您的代码。 您永远不知道,在某些年里,在代码错误修复期间,事件/处理程序是否设置为空。
始终写下 if 检查。
希望有帮助;)
ps:感谢您的性能计算。
pps:将其从事件案例编辑为回调示例。 感谢您的反馈...我在没有 Visual Studio 的情况下“编码”了该示例,并将我想到的示例调整为一个事件。 对困惑感到抱歉。
ppps:不知道它是否仍然适合线程......但我认为这是一个重要的原则。 另请检查 stackflow 的另一个线程
One thing is missed out as an answer for this question so far: It is dangerous to avoid the check for the null value.
The thing is: You never know who will use your code in which way. You never know, if in some years during a bug fix of your code the event/handler is set to null.
Always, write the if check.
Hope that helps ;)
ps: Thanks for the performance calculation.
pps: Edited it from a event case to and callback example. Thanks for the feedback ... I "coded" the example w/o Visual Studio and adjusted the example I had in mind to an event. Sorry for the confusion.
ppps: Do not know if it still fits to the thread ... but I think it is an important principle. Please also check another thread of stackflow