C#事件处理程序应该是exception安全的吗?

假设一个事件有多个处理程序,如果任何事件处理程序抛出exception,则不执行其余处理程序。

这是否意味着事件处理程序不应该抛出?

由于调用事件意味着调用者不了解被调用者:

  1. 在面对任意exception时,调用事件处理程序应该是健壮的。 调用堆栈中的所有内容都需要正确清理其自身的混乱,以防出现完全意外的情况。

  2. 事件处理程序应该真的避免抛出exception。

像空引用exception这样的东西在任何代码中都是不可原谅的,所以显然我们并不关心这一点。

文件IOexception之类的东西总是在写入或读取文件时发生,所以我会避免在事件处理程序中做IO。 如果在事件处理程序中执行IO是有意义的,那么它也会让senst处理处理程序中的IOexception。 不要将其传播回呼叫者。 找到一些方法来处理它。

在理想的世界里,是的。 尝试设计事件处理程序是个好主意,以便它们:

  • 不要抛出exception
  • 执行得非常快

不这样做会导致意外的副作用,因为事件的其他订阅者可能永远不会收到消息,或者很晚才收到消息。

不应该在事件处理程序中吞下exception ,但我通常也不建议抛出它们。 问题是通常没有好的地方可以捕获从事件处理程序中抛出的exception。

事件处理程序的设计模式会导致一些潜在的问题,因为它们都是间接调用的,可以是多播的。 由于它们是间接的,因此您必须小心并计划可以捕获它们可能引发的exception的位置。 由于它们是多播的,因此处理程序中的exception可能导致其他处理程序从未接收到该事件。

为什么事件处理程序与其他模式不一样? 有什么不同? exception意味着子程序告诉调用者它无法正常工作。 这意味着调用者必须对其执行某些操作。 如果一个处理程序正在执行一些对用例至关重要的处理,那么当它崩溃时,程序的其余部分必须停止是明智的。

这样做很诱人但最终取决于具体情况。

  • 如果您希望程序崩溃而不是冒着在错误或奇怪状态下运行的风险,那么无论如何都要抛出exception。
  • 如果你真的不在乎(仔细思考这个)并且只需要注意exception,那么包装在try / catch块中是完全合理的。
  • 如果你想让所有事件处理程序在崩溃之前运行(例如,可能某些处理程序释放资源),那么它需要更多努力…

在ASP.NET应用程序中,我只是让事件处理程序抛出exception。 这些exception将允许ASP.NET的自定义错误页面function工作。

在桌面应用程序中,我总是在任何事件处理程序的内容周围添加try / catch / finally块。 这样,任何exception总是被记录并显示给最终用户,但永远不会逃避事件处理程序,因此它们不会使应用程序崩溃。