C# BackgroundWorker 中未处理的异常

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/258662/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 20:15:35  来源:igfitidea点击:

Unhandled exceptions in BackgroundWorker

c#.netmultithreadingdebuggingbackgroundworker

提问by Ed Guiness

My WinForms app uses a number of BackgroundWorkerobjects 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.

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

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.

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

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?

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

采纳答案by Ed Guiness

If the operation raises an exception that your code does not handle, the BackgroundWorkercatches the exception and passes it into the RunWorkerCompletedevent 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.

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

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

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

回答by Stu Mackellar

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

默认情况下,它会被 BackgroundWorker 捕获并存储。来自 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.

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

回答by CallMeLaNN

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

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

Just recently, My RunWorkerCompleteddoes not catch the e.Errorwhen I simply Throw New Exception("Test")in DoWork. However Unhandled Exception raised. Catch in DoWorkis not the best practice thus e.Errorgot no meaning.

就在最近,我RunWorkerCompleted不赶e.Error的时候,我只是Throw New Exception("Test")DoWork。但是引发了未处理的异常。赶上DoWork不是最佳实践,因此e.Error没有意义。

When I try to create new Formwith new BackgroundWorker, e.Errorin RunWorkerCompletedhandled successfully. There should be something wrong in my complicated BackgroundWorker.

当我尝试创建新FormBackgroundWorkere.ErrorRunWorkerCompleted成功地处理。我的复杂的应该有问题BackgroundWorker

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

经过几天的谷歌搜索和调试,尝试出错。我在我的RunWorkerCompleted

  • Check for e.Errorfirst, then e.Cancelledand lastly e.Result
  • Do not get the e.Resultif e.Cancelled = True.
  • Do not get the e.Resultif e.Erroris not null(or Nothing) **
  • e.Error首先检查,然后e.Cancelled最后检查e.Result
  • 不要得到e.Resultif e.Cancelled = True
  • 不要得到e.Resultif e.Erroris not null(or Nothing) **

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

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



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

更新:e.Resultget 属性 .NET 设计它首先检查e.Error,如果有错误,那么他们将从.NET重新抛出相同的异常DoWork。这就是为什么我们得到 Unhandled 异常 inRunWorkerCompleted但实际上异常来自DoWork.

Here is the best practice to do in RunWorkerCompleted:

以下是最佳实践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:

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

Dim ThreadInfos as Dictionary(Of BackgroundWorker, YourObjectOrStruct)

You can easily access ThreadInfos(sender).Fieldanywhere you want.

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

回答by Vedran

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.

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

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.

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

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.

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

In short, to answer the original question:

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

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

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

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

使用RunWorkerCompleted 中的e.Error检查其他线程中的异常。

回答by TzOk

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.

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