【问题标题】:Why is Method.Invoke generating unhandled exceptions? Unable to catch even with TargetInvocationException为什么 Method.Invoke 会生成未处理的异常?即使使用 TargetInvocationException 也无法捕获
【发布时间】:2011-09-13 06:50:06
【问题描述】:

我正在尝试使用 Method.Invoke 来调用 Windows 窗体对话框,让用户执行一些选择/交互并继续执行。此调用调用发生在异步方法中。

虽然一切正常,但如果 windows 窗体上发生错误,则会引发未处理的异常,即使尝试捕获 TargetInvocationException 或只是 Exception

两种形式都在同一个 winforms 项目中。我知道执行异步调用的其他方法在哪里,但这只是为了说明问题。

表单对话框如下:

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

    private void btnOK_Click(object sender, EventArgs e)
    {
        throw new Exception("oh noes!");

        this.DialogResult = DialogResult.OK;
        this.Close();
    }

    private void btnCancel_Click(object sender, EventArgs e)
    {
        this.DialogResult = DialogResult.Cancel;
        this.Close();
    }

    public new DialogResult ShowDialog()
    {
        base.ShowDialog();
        return this.DialogResult;
    }
}

这是调用代码。 None 如果正在执行 catch 块,即使未调试也是如此(我的问题不是在 IDE 中调试异常,如提到的 here。以下导致未处理的异常)。

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

    private void Form1_Load(object sender, EventArgs e)
    {

        MethodInvoker simpleDelegate = new MethodInvoker(InvokeForm);
        IAsyncResult tag = simpleDelegate.BeginInvoke(null, null);
        simpleDelegate.EndInvoke(tag);
        MessageBox.Show("All done");
    }

    private void InvokeForm()
    {
        try
        {
            Type t = typeof(FakeDialog);
            MethodInfo showDialogMethod = t.GetMethod("ShowDialog", new Type[] { });
            object dialog = Activator.CreateInstance(t);
            System.Windows.Forms.DialogResult result = (System.Windows.Forms.DialogResult)showDialogMethod.Invoke(dialog, new object[] { });
            MessageBox.Show(result.ToString());

        }            
        catch (TargetInvocationException tie)
        {
            MessageBox.Show("Tie exception");
        }
        catch (Exception ex)
        {
            MessageBox.Show("general exception");
        }
    }
}

更新:

奇怪的是,我能够在调试运行时捕获异常(我确信 IDE 在这里提供帮助)。在不调试的情况下运行会导致未处理的异常。

此外,通过异步调用调用似乎没有什么不同。如果我只是调用 InvokeForm() (忽略所有 methodInvoker 的东西),我可以达到相同的结果。

使用 Visual Studio 2008 在 .NET 2.0 上运行。

【问题讨论】:

  • 哪个框架?我无法在 4.0 上重现;还有……你为什么要异步开始/结束?在这里一无所获(但让生活变得艰难)
  • 在框架 2.0 上。异步开始/结束只是为了有一个异步进程并在大型应用程序之外重现问题(在异步调用中调用对话框)。
  • 我已经重现了这个错误。 .net 2 和 vs2010 仅当您在 vs 之外运行 exe 时才会引发未处理的异常
  • 您可以通过将 Jit 调试添加到应用程序配置文件中来消除错误但它可以提供帮助。

标签: c# winforms reflection asynchronous


【解决方案1】:

好的,想通了。

代码的结果是未处理的异常。虽然在另一个类中对简单方法使用 Method.Invoke 会正常运行,但环境会随着表单中发生的异常源而变化。一个表单事件。 我最终在 Microsoft 支持上发现 unhandled exceptions in Windows Form events are not propagated up call stack. 这有一些非常有趣的原因(“Windows 窗体应用程序有一个顶级异常处理程序,允许程序在以下情况下继续运行它可以恢复”)。

这也证明了 Marc 提到的将事物放入 Load 事件中的内容。叹。所以这一切的原因现在很明显了。

至于代码在调试时运行良好(相对于没有运行),我想我应该感谢 JIT 调试器。 @fluf 指出,专门启用 JIT 调试器的结果与运行调试的结果相同。 @Marc Gravell,根据 VS 设置,这可能解释只有我和绒毛可以重现。有更多关于它的信息here,但这不是生产修复。

所以真正的解决方案是要么在事件处理程序本身中处理异常,要么使用上面 Microsoft 支持文章中提到的解决方案,这解决了我的问题。

【讨论】:

    【解决方案2】:

    我实际上无法从您的代码中重现,但是:Load 事件是.... 不同,如果您在 Load 中遇到异常,可能会发生一些奇怪的事情事件。我的建议是:将此代码移出Load 事件。在此处附加调试器也会改变行为(Heisenbug)也无济于事。

    【讨论】:

    • 您是否尝试过在 .NET 2.0 中进行回购?即使我将代码放在 btn_Click 中,结果也是一样的。我将代码放在 form_load 中的唯一原因是为了测试应用程序。真正的应用程序从一个线程调用它(我放置异步调用的原因,但现在看到它不需要重现)。
    • @MoSlo 我的测试项目确实是针对 2.0。
    【解决方案3】:

    没有看到 MethodInvoker 的声明,我只能猜测,但 InvokeForm() 方法可能在非 UI 线程上执行。

    MethodInvoker simpleDelegate = new MethodInvoker(InvokeForm); 
    IAsyncResult tag = simpleDelegate.BeginInvoke(null, null); 
    

    要显示一个对话框,您可以考虑重写如下:

    Action simpleDelegate = new Action(InvokeForm); 
    this.BeginInvoke(simpleDelegate);
    

    【讨论】:

    • 如果直接调用 InvokeForm() 会发生什么?
    • 同样的结果。奇怪的是,在调试中运行时,我能够捕捉到异常!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-11
    • 2018-10-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多