73

我的 WinForms 应用程序使用许多BackgroundWorker对象从数据库中检索信息。我正在使用 BackgroundWorker,因为它允许 UI 在长时间运行的数据库查询期间保持畅通,并且它为我简化了线程模型。

我在其中一些后台线程中偶尔会遇到 DatabaseExceptions,并且我在调试时在工作线程中目睹了这些异常中的至少一个。我相当有信心这些异常是超时,我认为它不时期望它是合理的。

我的问题是当这些后台工作线程之一中发生未处理的异常时会发生什么。

我认为我不能在另一个线程中捕获异常,但是我可以期望我的 WorkerCompleted 方法被执行吗?我可以询问 BackgroundWorker 的任何属性或方法是否有异常?

4

5 回答 5

79

如果该操作引发了您的代码未处理的异常,则BackgroundWorker捕获该异常并将其传递给RunWorkerCompleted事件处理程序,在该处理程序中它作为System.ComponentModel.RunWorkerCompletedEventArgs. 如果您在 Visual Studio 调试器下运行,则调试器将在 DoWork 事件处理程序中引发未处理异常的位置中断。

http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.dowork.aspx

于 2008-11-03T13:50:28.597 回答
34

我已经充分使用BackgroundWorker了一年多,并且非常了解它。

就在最近,我RunWorkerCompleted根本没赶上e.ErrorThrow New Exception("Test")DoWork. 但是引发了未处理的异常。赶上DoWork不是最好的做法,因此e.Error没有意义。

当我尝试使用 new 创建 newForm时,BackgroundWorker已成功处理。我的复杂中应该有问题。e.ErrorRunWorkerCompletedBackgroundWorker

经过几天的谷歌搜索和调试,尝试了一个错误。我在我的RunWorkerCompleted

  • 首先检查e.Error,然后检查e.Cancelled,最后检查e.Result
  • 不要得到e.Resultif e.Cancelled = True
  • 不要得到e.Resultif e.Erroris not null(or Nothing) **

**这是我想念的地方。如果您尝试使用e.Resultif e.Erroris not null(or Nothing),则会抛出 Unhandled Exception。


更新:e.Result获取属性 .NET 中设计它首先检查e.Error,如果有错误,那么他们将重新从 .NET 中抛出相同的异常DoWork。这就是为什么我们得到 Unhandled 异常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

如果您想要一个可供所有 DoWork、ProgressChanged 和 RunWorkerCompleted 访问的对象,请像这样使用:

Dim ThreadInfos as Dictionary(Of BackgroundWorker, YourObjectOrStruct)

您可以轻松访问ThreadInfos(sender).Field任何您想要的地方。

于 2010-04-14T09:46:16.223 回答
11

默认情况下,它将被 BackgroundWorker 捕获并存储。来自 MSDN:

如果操作引发了您的代码无法处理的异常,BackgroundWorker 将捕获该异常并将其传递给 RunWorkerCompleted 事件处理程序,在该处理程序中它作为 System.ComponentModel.RunWorkerCompletedEventArgs 的 Error 属性公开。如果您在 Visual Studio 调试器下运行,则调试器将在 DoWork 事件处理程序中引发未处理异常的位置中断。

于 2008-11-03T13:54:24.423 回答
4

正如已经指出的那样:

如果操作引发了您的代码无法处理的异常,BackgroundWorker 将捕获该异常并将其传递给 RunWorkerCompleted 事件处理程序,在该处理程序中它作为 System.ComponentModel.RunWorkerCompletedEventArgs 的 Error 属性公开。

每当您与原始线程交互时,这很重要。例如,如果您希望将异常结果写入表单上的某种标签中,那么您就不能在 BackgroundWorker 的 DoWork 中捕获异常,而是处理来自 RunWorkerCompletedEventArgs 的 e.Error。

如果您使用反射器分析 BackgroundWorker 代码,您会发现它的处理非常简单:您的 DoWork 在 try-catch 块中执行,异常只是传递给 RunWorkerCompleted。这就是为什么我不同意始终在 DoWork 事件中捕获所有异常的“首选”方法。

简而言之,回答原来的问题:

的 - 你可以指望你的 RunWorkerCompleted 总是被解雇。

使用RunWorkerCompleted 中的e.Error检查另一个线程中的异常。

于 2011-06-20T09:21:31.187 回答
4

这只会在没有附加调试器的情况下工作,当从 Visual Studio 运行时,调试器将在 DoWork 方法中捕获未经处理的异常并中断执行,但是您可以单击继续并到达 RunWorkerCompleted 并且您将能够读取异常通过 e.Error 字段。

于 2011-08-26T13:18:00.360 回答