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
Unhandled exceptions in BackgroundWorker
提问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 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
事件处理程序中,在该处理程序中,它作为 的 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 BackgroundWorker
over a years and really know it in deep.
我已经完全使用BackgroundWorker
了一年多,并且非常了解它。
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.
就在最近,我RunWorkerCompleted
不赶e.Error
的时候,我只是Throw New Exception("Test")
在DoWork
。但是引发了未处理的异常。赶上DoWork
不是最佳实践,因此e.Error
没有意义。
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
.
当我尝试创建新Form
新BackgroundWorker
,e.Error
在RunWorkerCompleted
成功地处理。我的复杂的应该有问题BackgroundWorker
。
After a few days googling and debugging, trying an error. I found this in my RunWorkerCompleted
:
经过几天的谷歌搜索和调试,尝试出错。我在我的RunWorkerCompleted
:
- Check for
e.Error
first, thene.Cancelled
and lastlye.Result
- Do not get the
e.Result
ife.Cancelled = True
. - Do not get the
e.Result
ife.Error
is notnull
(orNothing
) **
e.Error
首先检查,然后e.Cancelled
最后检查e.Result
- 不要得到
e.Result
ife.Cancelled = True
。 - 不要得到
e.Result
ife.Error
is notnull
(orNothing
) **
** This is where I miss. If you trying to use e.Result
if e.Error
is not null
(or Nothing
), Unhandled Exception will thrown.
**这是我想念的地方。如果您尝试使用e.Result
if e.Error
is not null
(或Nothing
),则会抛出未处理的异常。
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
.
更新:在e.Result
get 属性 .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).Field
anywhere 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 字段。