C# BackgroundWorker 中未处理的异常

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1044460/
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-06 06:52:39  来源:igfitidea点击:

Unhandled exceptions in BackgroundWorker

c#exceptionbackgroundworkerunhandled-exception

提问by Andy

I have a small WinForms app that utilizes a BackgroundWorker object to perform a long-running operation.

我有一个使用 BackgroundWorker 对象来执行长时间运行的操作的小型 WinForms 应用程序。

The background operation throws occasional exceptions, typically when somebody has a file open that is being recreated.

后台操作偶尔会抛出异常,通常是当有人打开正在重新创建的文件时。

Regardless of whether the code is run from the IDE or not .NET pops up an error dialog informing the user that an Unhandled exception has occurred. Compiling the code using the Release configuration doesn't change this either.

无论代码是否从 IDE 运行,.NET 都会弹出一个错误对话框,通知用户发生了未处理的异常。使用 Release 配置编译代码也不会改变这一点。

According to MSDN:

根据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 事件处理程序中引发未处理异常的点处中断。

I expect these exceptions to be thrown on occasion and would like to handle them in the RunWorkerCompleted event rather than in DoWork. My code works properly and the error is handled correctly within the RunWorkerCompleted event but I can't for the life of me figure out how to stop the .NET error dialog complaining about the "Unhandled exception" from occurring.

我希望偶尔会抛出这些异常,并希望在 RunWorkerCompleted 事件中而不是在 DoWork 中处理它们。我的代码工作正常,错误在 RunWorkerCompleted 事件中得到了正确处理,但我终其一生都无法弄清楚如何阻止 .NET 错误对话框抱怨“未处理的异常”发生。

Isn't the BackgroundWorker supposed to catch that error automagically? Isn't that what the MSDN documentation states? What do I need to do to inform .NET that this error isbeing handled while still allowing the exception to propage into the Error property of RunWorkerCompletedEventArgs?

BackgroundWorker 不应该自动捕获该错误吗?这不是 MSDN 文档所说的吗?我需要做什么做的通知.NET,这个错误被处理,同时仍允许例外propage到RunWorkerCompletedEventArgs的错误属性?

采纳答案by Judah Gabriel Himango

What you're describing is not the defined behavior of BackgroundWorker. You're doing something wrong, I suspect.

您所描述的不是 BackgroundWorker 的定义行为。你做错了什么,我怀疑。

Here's a little sample that proves BackgroundWorker eats exceptions in DoWork, and makes them available to you in RunWorkerCompleted:

这里有一个小示例,证明 BackgroundWorker 处理DoWork 中的异常,并在RunWorkerCompleted 中使它们可用:

var worker = new BackgroundWorker();
worker.DoWork += (sender, e) => 
    { 
        throw new InvalidOperationException("oh shiznit!"); 
    };
worker.RunWorkerCompleted += (sender, e) =>
    {
        if(e.Error != null)
        {
            MessageBox.Show("There was an error! " + e.Error.ToString());
        }
    };
worker.RunWorkerAsync();

My psychic debugging skills are revealing your problem to me: You are accessing e.Result in your RunWorkerCompleted handler -- if there's an e.Error, you must handle it without accessing e.Result. For example, the following code is bad, bad, bad, and will throw an exception at runtime:

我的心灵调试技能向我揭示了您的问题:您正在 RunWorkerCompleted 处理程序中访问 e.Result——如果存在 e.Error,您必须在不访问 e.Result 的情况下处理它。例如下面的代码是坏的,坏的,坏的,运行时会抛出异常:

var worker = new BackgroundWorker();
worker.DoWork += (sender, e) => 
    { 
        throw new InvalidOperationException("oh shiznit!"); 
    };
worker.RunWorkerCompleted += (sender, e) =>
    {
        // OH NOOOOOOOES! Runtime exception, you can't access e.Result if there's an
        // error. You can check for errors using e.Error.
        var result = e.Result; 
    };
worker.RunWorkerAsync();

Here's a proper implementation of the RunWorkerCompleted event handler:

这是 RunWorkerCompleted 事件处理程序的正确实现:

private void RunWorkerCompletedHandler(object sender, RunWorkerCompletedEventArgs e)
{
    if (e.Error == null)
    {
       DoSomethingWith(e.Result); // Access e.Result only if no error occurred.
    }
}

VOILA, you won't receive runtime exceptions.

瞧,您不会收到运行时异常。

回答by Bobby Cannon

[Edit]

[编辑]

Judah has a great point. My example pointed out the specifics of handling the error but my code would actually cause another exception if an exception was never hit in the DoWork method. This example is OK due to the fact that we are specifically showing the error handling capabilities of the BackgroundWorker. However if you are not checking the error parameter against null then this could be your issue.

犹大有一个很好的观点。我的示例指出了处理错误的细节,但如果在 DoWork 方法中从未遇到异常,我的代码实际上会导致另一个异常。这个例子是可以的,因为我们专门展示了 BackgroundWorker 的错误处理能力。但是,如果您没有针对 null 检查错误参数,那么这可能是您的问题。

[/Edit]

[/编辑]

I don't see the same results. Can you post a little code? Here is my code.

我没有看到相同的结果。你能贴一个小代码吗?这是我的代码。

private void Form1_Load(object sender, EventArgs e)
{
    BackgroundWorker worker = new BackgroundWorker();
    worker.DoWork += new DoWorkEventHandler(worker_DoWork);
    worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
    worker.RunWorkerAsync();
}

void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    // Will cause another exception if an exception didn't occur.
    // We should be checking to see if e.Error is not "null".
    textBox1.Text = "Error? " + e.Error;
}

void worker_DoWork(object sender, DoWorkEventArgs e)
{
    for (int i = 0; i < 10; i++)
    {
        if (i < 5)
        {
            Thread.Sleep(100);
        }
        else
        {
            throw new Exception("BOOM");
        }   
    }
}

Program Output:

程序输出:

Error? System.Exception: BOOM at BackgroundException.Form1.worker_DoWork(Object sender, DoWorkEventArgs e) in D:\Workspaces\Sandbox\BackgroundException\BackgroundException\Form1.cs:line 43 at System.ComponentModel.BackgroundWorker.OnDoWork(DoWorkEventArgs e) at System.ComponentModel.BackgroundWorker.WorkerThreadStart(Object argument)

错误?System.Exception: BOOM at BackgroundException.Form1.worker_DoWork(Object sender, DoWorkEventArgs e) in D:\Workspaces\Sandbox\BackgroundException\BackgroundException\Form1.cs:line 43 at System.ComponentModel.BackgroundWorker.OnDoWork(DoWorkEventArgs e) at System .ComponentModel.BackgroundWorker.WorkerThreadStart(对象参数)

An interesting article that looks similar to your question. It has a section on handling exceptions.

一篇有趣的文章,看起来与您的问题相似。它有一个关于处理异常的部分。

http://www.developerdotstar.com/community/node/671

http://www.developerdotstar.com/community/node/671

回答by Mark Cranness

I would add to the MSDN text:

我会添加到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 事件处理程序中引发未处理异常的点处中断。

... AND the debugger will report the exception as "~Exception was unhandled by user code"

...并且调试器会将异常报告为“~异常未被用户代码处理”

Solution: Don't run under the debugger and it works as expected: Exception caught in e.Error.

解决方案:不要在调试器下运行,它按预期工作:在 e.Error 中捕获异常。

回答by Rich

This is an old question, but I found it while Googling the same symptoms. Posting this in case someone else finds it for the same reason.

这是一个老问题,但我在谷歌搜索相同症状时发现了它。发布此信息以防其他人出于同样的原因找到它。

Judah's answer is right, but it isn't the only reason the "unhandled exception in user code" dialog can appear. If an exception is thrown from inside a constructoron the background thread then that exception will cause the dialog immediately, and won't be passed to the RunWorkerCompleted event. If you move the offending code outside of any constructors (to any other method) it works as expected.

Judah 的回答是正确的,但这并不是“用户代码中未处理的异常”对话框出现的唯一原因。如果后台线程的构造函数内部抛出异常则该异常将立即引发对话框,并且不会传递给 RunWorkerCompleted 事件。如果您将有问题的代码移到任何构造函数之外(到任何其他方法),它会按预期工作。

回答by Cavaleiro

I had the same problem and i was already applying the Judah answer before i found this topic after some googling.

我遇到了同样的问题,在谷歌搜索后发现这个话题之前,我已经在应用犹大的答案。

Well, imo the Judah answer is partially correct. I found a better answer here

好吧,犹大的回答是部分正确的。我在这里找到了更好的答案

The debugger is making the work well, if you run the application in "real-world conditions", the RunWorkerCompleted deals with the exception as expected and the application behavior is also the expected.

调试器使工作正常,如果您在“真实世界条件”下运行应用程序,RunWorkerCompleted 按预期处理异常,应用程序行为也是预期的。

I hope this answer helps.

我希望这个答案有帮助。