[英]Event Exception Handling In Framework
我正在寻找有关处理事件异常的最佳实践的一些指导。 当前,当我的应用程序中引发异常时,该异常消息会显示在弹出对话框中,然后单击确定后,应用程序将重新启动。 我看到的问题是,某些第三方库的事件处理程序中发生了许多异常,并且这些异常被吞噬且从未显示,因为它们位于后台线程中。 这里有一些人们已经想到的解决方案,我想知道其中的任何一种都是最好的方法。
让我们以列出方式来讨论您的选择:
1)将后台线程转发到应用程序中每个事件处理程序中的UI线程。
你不应该,你不能! 因为:
2)将事件包装在另一个类中,该类具有对调用该事件的每个方法的尝试/捕获。 然后,如果发生异常,则catch会将异常转发到UI线程。
3)可以访问第三方库,并在调用事件的位置进行尝试/捕获,然后可以通过全局事件将其转发到主应用程序。
实际上,这是一个错误的选择, 即使可以 ,您也不应更改第三方库的代码。 因为:
那你该怎么办? 答案是您当前正在做的事情:
每当引发任何异常时,记录该异常都会重新启动您的过程,然后在过程中的某个时刻将记录的错误发送到您的电子邮件中,然后开始修复它们。
以上都不是。 而是将Application
和AppDomain
上的事件挂钩以获取未处理的异常。
进一步的信息: WPF应用Application.DispatcherUnhandledException
的全局异常处理事件Application.DispatcherUnhandledException
仅针对在主UI线程上引发的异常触发。 但是, AppDomain.CurrentDomain.UnhandledException
应该在任何线程中的任何未处理的异常上触发(不幸的是,无法阻止应用程序在到达此处后关闭)。
对最佳做法进行了一些快速研究,发现建议您使用try\\catch
块手动处理后台线程上的异常。 阅读本页http://www.albahari.com/threading/上的异常部分,并查看此StackOverflow问题: 在单独的线程上捕获未处理的异常
如果钩住AppDomain.UnhandledException事件,那么问题就不在于它们可能在后台线程上回调,而是第三方库明确吞下了处理程序引发的异常。 这是一个表现不佳的库,但是,由于您正在编写事件处理程序代码,因此可以在事件处理程序中捕获异常并强制应用程序关闭。
由于不能通过引发异常来停止第三方库,因此可以通过调用以下命令来强制终止线程:
Thread.CurrentThread.Abort();
Thread.Abort()
通常被认为是一种不好的做法,但是在这里它的危险性要小一些,因为您正在中止自己,因此不会将异常注入到可能令人讨厌的位置(您也知道线程不在非托管上下文中) ,因此它会立即中止。)这仍然是一个令人讨厌的骇客,但是第三方应用程序却没有给您太多选择。 ThreadAbortException不能被“停止”,因此第三方代码将在其异常处理程序结束时终止其线程(即使他们试图吞没它)。 如果第三方库确实很讨厌,它可能会在其catch或finally块中调用许多代码,甚至使用肮脏的技巧像启动其他线程一样保持活动,但这样做必须非常恶意。
为了获得友好的错误消息行为,您可以使用SynchronizationContext或Dispatcher将Exception编组到UI线程,以调用异常处理程序显示(最简单的方法可能是重新抛出该异常;我建议将其嵌入为InnerException。这样您就不会丢失堆栈跟踪。)
如果您真的不信任该库(并且即使通过捕获并最终阻止也不希望给予它生存的机会),则可以使用阻止调用显式地编组到UI线程(以友好的方式显示错误消息)方式),然后调用Environment.FailFast()
杀死您的进程。 这是终止的一种特别苛刻的方式(它不会调用任何清除代码,并且从字面上尽可能快地删除该过程),但是,如果应用程序状态已非常损坏,则它可以最大程度地减少产生任何潜在破坏性副作用的可能性。 这里需要注意的一件事是,UI线程可能会被绑定到第三方代码的某些其他UI调用阻止。 如果发生这种情况,应用程序将死锁。 同样,这将是非常恶意的事情,因此您可能会忽略它。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.