73

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

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

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

根据MSDN

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

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

BackgroundWorker 不应该自动捕获该错误吗?这不是 MSDN 文档所说的吗?我需要做什么来通知 .NET 这个错误正在被处理,同时仍然允许异常传播到 RunWorkerCompletedEventArgs 的 Error 属性中?

4

5 回答 5

139

您所描述的不是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();

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

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();

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

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

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

于 2009-06-25T15:34:03.250 回答
41

我将添加到MSDN 文本中

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

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

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

于 2011-03-09T11:10:03.933 回答
2

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

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

于 2012-03-20T21:59:58.503 回答
2

[编辑]

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

[/编辑]

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

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");
        }   
    }
}

程序输出:

错误?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(对象参数)

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

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

于 2009-06-25T15:10:38.303 回答
0

我遇到了同样的问题,并且在经过一番谷歌搜索后找到这个主题之前,我已经在应用 Judah 的答案了。

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

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

我希望这个答案有帮助。

于 2015-04-26T16:02:27.153 回答