繁体   English   中英

BackgroundWorker中未处理的异常

[英]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与新BackgroundWorkere.ErrorRunWorkerCompleted成功处理。 我复杂的BackgroundWorker应该有问题。

经过几天的谷歌搜索和调试,尝试执行错误。 我在RunWorkerCompleted找到了这个:

  • 首先检查e.Error ,然后检查e.Cancelled ,最后e.Result
  • 如果e.Cancelled = True不要获取e.Result
  • 不要让e.Result如果e.Errornull (或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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM