BackgroundWorker 中未处理的异常

发布于 2024-07-07 23:07:52 字数 485 浏览 10 评论 0原文

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

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

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

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

My WinForms app uses a number of BackgroundWorker objects to retrieve information from a database. I'm using BackgroundWorker because it allows the UI to remain unblocked during long-running database queries and it simplifies the threading model for me.

I'm getting occasional DatabaseExceptions in some of these background threads, and I have witnessed at least one of these exceptions in a worker thread while debugging. I'm fairly confident these exceptions are timeouts which I suppose its reasonable to expect from time to time.

My question is about what happens when an unhandled exception occurs in one of these background worker threads.

I don't think I can catch an exception in another thread, but can I expect my WorkerCompleted method to be executed? Is there any property or method of the BackgroundWorker I can interrogate for exceptions?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

燕归巢 2024-07-14 23:07:52

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

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

If the operation raises an exception that your code does not handle, the BackgroundWorker catches the exception and passes it into the RunWorkerCompleted event handler, where it is exposed as the Error property of System.ComponentModel.RunWorkerCompletedEventArgs. If you are running under the Visual Studio debugger, the debugger will break at the point in the DoWork event handler where the unhandled exception was raised.

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

叹梦 2024-07-14 23:07:52

我已经充分使用 BackgroundWorker 多年了,并且真正了解它。

就在最近,当我简单地在 DoWork< 中抛出 New Exception("Test") 时,我的 RunWorkerCompleted 没有捕获 e.Error /代码>。 然而引发了未处理的异常。 DoWork 中的 Catch 不是最佳实践,因此 e.Error 没有任何意义。

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

经过几天的谷歌搜索和调试,尝试出现错误。 我在我的 RunWorkerCompleted 中发现了这一点:

  • 首先检查 e.Error,然后检查 e.Cancelled,最后检查 e.Result
  • 如果e.Cancelled = True,则不会获取e.Result
  • 如果 e.Error 不为 null(或 Nothing),则不会获取 e.Result **

**这就是我想念的地方。 如果您尝试使用 e.Result,如果 e.Error 不是 null(或 Nothing),未处理的异常会抛出。


更新:
e.Result get属性中,.NET设计它首先检查e.Error,如果出现错误,那么它们将从重新抛出相同的异常执行工作。 这就是为什么我们在 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< /code> 任何你想要的地方。

I am fully using BackgroundWorker over a years and really know it in deep.

Just recently, My RunWorkerCompleted does not catch the e.Error when I simply Throw New Exception("Test") in DoWork. However Unhandled Exception raised. Catch in DoWork is not the best practice thus e.Error got no meaning.

When I try to create new Form with new BackgroundWorker, e.Error in RunWorkerCompleted handled successfully. There should be something wrong in my complicated BackgroundWorker.

After a few days googling and debugging, trying an error. I found this in my RunWorkerCompleted:

  • Check for e.Error first, then e.Cancelled and lastly e.Result
  • Do not get the e.Result if e.Cancelled = True.
  • Do not get the e.Result if e.Error is not null (or Nothing) **

** This is where I miss. If you trying to use e.Result if e.Error is not null (or Nothing), Unhandled Exception will thrown.


UPDATE:
In the e.Result get property .NET design it to check for e.Error first, if got error, then they will re-throw the same exception from DoWork. That is why we get Unhandled exception in RunWorkerCompleted but actually the exception is come from DoWork.

Here is the best practice to do in 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

If you want an object that accessible to all DoWork, ProgressChanged and RunWorkerCompleted, use like this:

Dim ThreadInfos as Dictionary(Of BackgroundWorker, YourObjectOrStruct)

You can easily access ThreadInfos(sender).Field anywhere you want.

指尖上的星空 2024-07-14 23:07:52

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

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

By default it will be caught and stored by the BackgroundWorker. From MSDN:

If the operation raises an exception that your code does not handle, the BackgroundWorker catches the exception and passes it into the RunWorkerCompleted event handler, where it is exposed as the Error property of System.ComponentModel.RunWorkerCompletedEventArgs. If you are running under the Visual Studio debugger, the debugger will break at the point in the DoWork event handler where the unhandled exception was raised.

¢蛋碎的人ぎ生 2024-07-14 23:07:52

正如已经指出的:

如果操作引发异常
您的代码无法处理,
BackgroundWorker 捕获异常
并将其传递到
RunWorkerCompleted 事件处理程序,
它被暴露为错误
的财产
System.ComponentModel.RunWorkerCompletedEventArgs。

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

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

简而言之,回答最初的问题:

- 您可以指望您的 RunWorkerCompleted 始终被解雇。

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

As it was already noted:

If the operation raises an exception
that your code does not handle, the
BackgroundWorker catches the exception
and passes it into the
RunWorkerCompleted event handler,
where it is exposed as the Error
property of
System.ComponentModel.RunWorkerCompletedEventArgs.

This is important whenever you're interacting with the original thread. For example if you want the result of your exception to be written in some kind of a label on your form, that's when you mustn't catch the exception in the DoWork of the BackgroundWorker, but instead handle the e.Error from RunWorkerCompletedEventArgs.

If you analyze the BackgroundWorker code with reflector you can see its all handled pretty straightforward:
Your DoWork gets executed in a try-catch block, and the exception is just passed to RunWorkerCompleted.
Which is the reason why I disagree with the 'preferred' method of always catching all your exceptions in the DoWork event.

In short, to answer the original question:

Yes - you can count on your RunWorkerCompleted to always be fired.

Use e.Error from RunWorkerCompleted to check for exceptions in the other thread.

撑一把青伞 2024-07-14 23:07:52

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

This will work only without the debugger attached, when run from Visual Studio, the debugger will catch the unhanded exception in DoWork method and will break the execution, however you may click continue and RunWorkerCompleted will be reached and you'll be able to read exception via the e.Error field.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文