BackoundWorker 中的未处理异常

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

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

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

根据 MSDN:

如果操作引发了代码不能处理的异常,Background Worker 将捕获该异常并将其传递给 RunWorkerCompleted 事件处理程序,在该处将该异常公开为 System 的 Error 属性。组件模型。.::.RunWorkerCompletedEventArgs.如果在 VisualStudio 调试器下运行,则调试器将在 DoWork 事件处理程序中引发未处理异常的点中断。

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

后台工作者不是应该自动捕捉错误吗?MSDN 文档不是这么说的吗?我需要做什么来通知。NET,这个错误 正在处理,同时仍然允许异常传播到 RunWorkerCompletedEventArgs 的 Error 属性?

54612 次浏览

[编辑]

犹大说得很有道理。我的示例指出了处理该错误的细节,但是如果 DoWork 方法中从未碰到异常,我的代码实际上会导致另一个异常。这个示例是可以的,因为我们专门展示了 Background Worker 的错误处理能力。但是,如果您没有检查错误参数是否为 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");
}
}
}

程序输出:

错误? 系统。异常: 在 Form1.worker _ DoWork (Object 发件人,DoWorkEventArgs e) D: Workspace Sandbox 四十三岁 系统、组件模型、后台工作者、 OnDoWork (DoWorkEventArgs E)在 系统。组件模型 论点)

一篇与你的问题相似的有趣的文章,它有一个关于处理异常的章节。

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

你所描述的不是背景工作者的固定行为。我怀疑你做错了什么。

下面的一个小例子证明了 Background Worker 在 DoWork中吃掉异常,并在 完成中为您提供异常:

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

我的心理调试技能正在向我揭示你的问题: 您正在访问 e. Result 在您的 RunWorkerCompleted 处理程序中——如果有 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();

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

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

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

我想在 MSDN 文本中加上:

如果操作引发了代码不能处理的异常,Background Worker 将捕获该异常并将其传递给 RunWorkerCompleted 事件处理程序,在该处将该异常公开为 System 的 Error 属性。组件模型。.::.RunWorkerCompletedEventArgs.如果在 VisualStudio 调试器下运行,则调试器将在 DoWork 事件处理程序中引发未处理异常的点中断。

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

解决方案: 不要在调试器下运行,它可以正常工作。

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

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

我有同样的问题,我已经应用犹大的答案之前,我发现这个主题后,一些谷歌。

嗯,我认为犹大的答案有一部分是正确的。我找到了一个更好的答案

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

我希望这个答案能有所帮助。