3

假设以下情况。表单有一个按钮,单击该按钮可启动后台工作人员。在 RunWorkerCompleted 事件处理程序中有一段代码会引发未处理的异常。表单从 Application.Run 方法开始。

public partial class FormMain : Form
{
    public FormMain()
    {
        InitializeComponent();
    }

    private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        throw new Exception();
    }

    private void button_Click(object sender, EventArgs e)
    {
        backgroundWorker.RunWorkerAsync();
    }
}

问题是 Visual Studio 在 Application.Run 调用处中断,而不是在 FormMain.backgroundWorker_RunWorkerCompleted 方法中的“throw new Exception()”处中断。最重要的是,真正的异常被 TargetInvocationException 包裹,调用堆栈被简化为 Program.Main 方法,因此无法检查导致异常的代码。

如何防止这种包装?我在做一些本质上错误的事情吗?

从 TargetInvocationException 提供的调用堆栈来看,堆积了很多调用方法,对于我对消息循环的基本理解和对线程的不太基本的理解来说太多了。

编辑:我知道 TargetInvocationException 中有 InnerException 属性,并且可以通过查看那里来跟踪错误,但这不是问题。问题是如何在使用 TargetInvocationException 包装真正的异常之前停止 Visal Studio,这样我就可以使用 VS IDE 提供的所有这些不错的调试功能。

4

1 回答 1

3

是的,这是使 RunWorkerCompleted 事件在 UI 线程上运行的魔法带来的一个不幸的副作用。您编写的任何代码都没有使它运行,因此调试器无法显示任何相关内容,但程序中仍然涉及的最后一条语句,即启动消息循环的 Application.Run() 调用。

您必须通过在抛出异常时强制调试器停止来调试它。Debug + Exceptions,勾选 CLR exceptions 的 Throw 复选框。还要注意当你在没有调试器的情况下运行它时的行为,你会得到命运之轮对话框。使用 Application.SetUnhandledExceptionMode() 修复该问题。

于 2012-05-28T15:04:16.423 回答