BackgroundWorker中未处理的异常

And*_*ndy 67 c# exception backgroundworker unhandled-exception

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

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

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

根据MSDN:

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

我希望有时抛出这些异常,并希望在RunWorkerCompleted事件而不是DoWork中处理它们.我的代码正常工作,并且在RunWorkerCompleted事件中正确处理错误,但我不能在我的生活中弄清楚如何停止.NET错误对话框抱怨发生"未处理的异常".

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

Jud*_*ngo 125

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

下面是一个小样本,证明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();
Run Code Online (Sandbox Code Playgroud)

我的通灵调试技巧向我揭示了你的问题:你正在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();
Run Code Online (Sandbox Code Playgroud)

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

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

VOILA,您将不会收到运行时异常.

  • @Judah:谢谢你.你救了我很多时间.这有点魔力,我真的希望.NET会抛出更多的鼻子异常("当`BackgroundWorker DoWork`抛出异常时,可能无法访问Result属性"),而不是试图做正确的事情而且只是令人困惑的事情. (4认同)

小智 37

我会添加到MSDN文本:

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

...并且调试器将异常报告为"〜用户代码未处理异常"

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

  • 感谢那.我真正想知道的是为什么它在地球上表现得像这样.无法调试`RunWorkerCompleted`事件的异常处理. (4认同)
  • @yu_ominae:并非不可能。每当调试器因异常而中断时,您实际上可以按 F5(继续)让 BackgroundWorker 捕获异常,并且执行将在“RunWorkerCompleted”中按预期继续。 (3认同)
  • 马克 - 你真的应该考虑更新你的答案以纳入安德斯的评论。 (2认同)