我的WinForms应用程序使用许多BackgroundWorker个对象从数据库中检索信息。我正在使用BackgroundWorker,因为它允许UI在长时间运行的数据库查询期间保持畅通无阻,并简化了我的线程模型。
我在其中一些后台线程中偶尔会遇到DatabaseExceptions,并且在调试时我在工作线程中至少目睹了其中一个异常。我非常有信心这些例外是超时,我认为它不时是合理的。
我的问题是当其中一个后台工作线程发生未处理的异常时会发生什么。
我认为我不能在另一个线程中捕获异常,但是我可以期望我的WorkerCompleted方法被执行吗?我是否可以查询异常的BackgroundWorker的任何属性或方法?
答案 0 :(得分:77)
如果操作引发了代码无法处理的异常,BackgroundWorker
将捕获异常并将其传递到RunWorkerCompleted
事件处理程序,并将其公开为{{1的Error属性}}。如果您在Visual Studio调试器下运行,则调试器将在DoWork事件处理程序中出现未处理的异常的位置中断。
http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.dowork.aspx
答案 1 :(得分:34)
我在一年多时间内完全使用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.Result
<。li>,请勿获取e.Cancelled = True
e.Result
不是e.Error
(或null
)** Nothing
**这是我想念的地方。如果您e.Result
e.Error
不是null
(或Nothing
)时尝试使用e.Result
,则会抛出未处理的异常。
<强>更新强>
在e.Error
获取属性.NET设计中,首先检查DoWork
,如果出现错误,则会从RunWorkerCompleted
重新抛出相同的异常。这就是我们在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
中的最佳做法:
Dim ThreadInfos as Dictionary(Of BackgroundWorker, YourObjectOrStruct)
如果您想要一个可供所有DoWork,ProgressChanged和RunWorkerCompleted访问的对象,请使用如下:
ThreadInfos(sender).Field
您可以随时随地轻松访问{{1}}。
答案 2 :(得分:10)
默认情况下,它将被BackgroundWorker捕获并存储。来自MSDN:
如果操作引发了代码无法处理的异常,则BackgroundWorker会捕获异常并将其传递给RunWorkerCompleted事件处理程序,并将其作为System.ComponentModel.RunWorkerCompletedEventArgs的Error属性公开。如果您在Visual Studio调试器下运行,则调试器将在DoWork事件处理程序中出现未处理的异常的位置中断。
答案 3 :(得分:4)
正如已经指出的那样:
如果操作引发异常 您的代码无法处理, BackgroundWorker捕获异常 并把它传递给 RunWorkerCompleted事件处理程序, 它作为错误公开的地方 的财产 System.ComponentModel.RunWorkerCompletedEventArgs。
每当您与原始主题进行交互时,这一点非常重要。例如,如果您希望将异常的结果写入表单上的某种标签,那么您必须在BackgroundWorker的DoWork中捕获异常,而是从RunWorkerCompletedEventArgs处理e.Error。 / p>
如果使用反射器分析BackgroundWorker代码,您可以看到它的处理非常简单: 您的DoWork在try-catch块中执行,异常只传递给RunWorkerCompleted。 这就是为什么我不同意总是在DoWork事件中捕获所有异常的“首选”方法的原因。
简而言之,回答原来的问题:
是 - 您可以指望您的RunWorkerCompleted始终被解雇。
使用RunWorkerCompleted中的 e.Error 来检查其他线程中的异常。
答案 4 :(得分:3)
这只能在没有附加调试器的情况下工作,当从Visual Studio运行时,调试器将在DoWork方法中捕获无法处理的异常并将中断执行,但是您可以单击继续并且将到达RunWorkerCompleted并且您将能够通过e.Error字段读取异常。