[英]Unhandled exceptions in BackgroundWorker
我的WinForms应用程序使用许多BackgroundWorker对象从数据库检索信息。 我之所以使用BackgroundWorker,是因为它允许UI在长时间运行的数据库查询期间保持畅通无阻,并且为我简化了线程模型。
我在其中某些后台线程中偶尔遇到DatabaseException,并且在调试时在工作线程中目睹了至少其中一种异常。 我非常有信心这些例外是超时,我认为这是不时发生的合理预期。
我的问题是关于当未处理的异常在这些背景下的一个工作线程时会发生什么。
我不认为我能赶上在另一个线程的异常,但我可以指望执行我的WorkerCompleted方法? 是否可以查询BackgroundWorker的任何属性或方法来处理异常?
如果操作抛出一个异常,你的代码不处理,该BackgroundWorker
捕捉异常,并将其传递到RunWorkerCompleted
事件处理程序,它被暴露的错误属性System.ComponentModel.RunWorkerCompletedEventArgs
。 如果您在Visual Studio调试器下运行,则调试器将在DoWork事件处理程序中引发未处理异常的点处中断。
http://msdn.microsoft.com/zh-CN/library/system.componentmodel.backgroundworker.dowork.aspx
多年来,我一直在充分使用BackgroundWorker
,并且对它非常了解。
就在最近,我RunWorkerCompleted
不赶e.Error
时,我只是Throw New Exception("Test")
中DoWork
。 但是引发了未处理的异常。 在DoWork
捕获不是最佳实践,因此e.Error
没有意义。
当我试图创造新的Form
与新BackgroundWorker
, e.Error
在RunWorkerCompleted
成功处理。 我复杂的BackgroundWorker
应该有问题。
经过几天的谷歌搜索和调试,尝试执行错误。 我在RunWorkerCompleted
找到了这个:
e.Error
,然后检查e.Cancelled
,最后e.Result
e.Cancelled = True
不要获取e.Result
。 e.Result
如果e.Error
不null
(或Nothing
)** **这是我想念的地方。 如果在e.Error
不为null
(或Nothing
)的情况下尝试使用e.Result
,则将引发未处理的异常。
更新:在e.Result
get属性.NET中,将其设计为首先检查e.Error
,如果遇到错误,则它们将从DoWork
重新引发相同的异常。 这就是为什么我们在RunWorkerCompleted
获得Unhandled异常,但实际上该异常来自DoWork
。
这是在RunWorkerCompleted
执行的最佳实践:
If e.Error IsNot Nothing Then
' Handle the error here
Else
If e.Cancelled Then
' Tell user the process canceled here
Else
' Tell user the process completed
' and you can use e.Result only here.
End If
End If
如果要使所有DoWork,ProgressChanged和RunWorkerCompleted都可以访问的对象,请像这样使用:
Dim ThreadInfos as Dictionary(Of BackgroundWorker, YourObjectOrStruct)
您可以在任意位置轻松访问ThreadInfos(sender).Field
。
默认情况下,它将由BackgroundWorker捕获并存储。 从MSDN:
如果该操作引发了代码无法处理的异常,则BackgroundWorker将捕获该异常并将其传递到RunWorkerCompleted事件处理程序,在该事件处理程序中将其公开为System.ComponentModel.RunWorkerCompletedEventArgs的Error属性。 如果您在Visual Studio调试器下运行,则调试器将在DoWork事件处理程序中引发未处理异常的点处中断。
因为它已经指出:
如果该操作引发了代码无法处理的异常,则BackgroundWorker将捕获该异常并将其传递到RunWorkerCompleted事件处理程序,在该事件处理程序中将其公开为System.ComponentModel.RunWorkerCompletedEventArgs的Error属性。
每当您与原始线程进行交互时,这一点都很重要。 例如,如果您希望将异常的结果以某种形式的标签写在表单上,那么您就不必在BackgroundWorker的DoWork中捕获该异常,而应处理RunWorkerCompletedEventArgs中的e.Error。
如果使用反射器分析BackgroundWorker代码,则可以看到其处理起来非常简单:DoWork在try-catch块中执行,并且该异常仅传递给RunWorkerCompleted。 这就是为什么我不同意总是在DoWork事件中捕获所有异常的“首选”方法的原因。
简而言之,要回答原始问题:
是的 -您可以依靠RunWorkerCompleted使其始终被解雇。
使用RunWorkerCompleted中的e.Error检查另一个线程中的异常。
从Visual Studio运行时,调试器将在DoWork方法中捕获未处理的异常并中断执行,这仅在没有附加调试器的情况下起作用,但是您可以单击“继续”,并且将达到RunWorkerCompleted,并且您将能够读取异常经由e.Error字段。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.