C# 为什么方法.Invoke会生成未处理的异常?即使存在TargetInvocationException,也无法捕获

C# 为什么方法.Invoke会生成未处理的异常?即使存在TargetInvocationException,也无法捕获,c#,winforms,reflection,asynchronous,C#,Winforms,Reflection,Asynchronous,我正在尝试使用Method.Invoke调用windows窗体对话框,让用户执行一些选择/交互并继续执行。此调用在异步方法中发生 虽然一切正常,但如果windows窗体上发生错误,则会引发未处理的异常,即使在尝试捕获TargetInvocationException或just exception时也是如此 这两个表单位于同一个winforms项目中。我知道执行异步调用的其他方法在哪里,但这只是为了说明问题 “表单”对话框如下所示: public partial class FakeDialog

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

虽然一切正常,但如果windows窗体上发生错误,则会引发未处理的异常,即使在尝试捕获TargetInvocationException或just 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;
    }
}
Action simpleDelegate = new Action(InvokeForm); 
this.BeginInvoke(simpleDelegate);
这是呼叫代码。如果正在执行catch块,则无,即使在未调试时也是如此(我的问题不是调试IDE中的异常,如前所述。以下将导致未处理的异常)

更新:

奇怪的是,我在运行调试时能够捕捉到异常(我相信IDE在这里会有所帮助)。在不进行调试的情况下运行会导致未处理的异常

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");
        }
    }
}
此外,通过异步调用调用似乎没有什么不同。如果我只调用InvokeForm()(忽略所有methodInvoker的内容),我可以获得相同的结果


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

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

MethodInvoker simpleDelegate = new MethodInvoker(InvokeForm); 
IAsyncResult tag = simpleDelegate.BeginInvoke(null, null); 
为了显示一个对话框,您可以考虑将其重写如下:

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;
    }
}
Action simpleDelegate = new Action(InvokeForm); 
this.BeginInvoke(simpleDelegate);

我实际上无法从您的代码中重新编程,但是:
Load
事件是。。。。不同的是,如果在
Load
事件中出现异常,可能会发生一些奇怪的事情。简单地说,我的建议是:将此代码移出
Load
事件。在这里附加调试器也无助于改变行为(Heisenbug)。

好的,解决它

代码的结果是未处理的异常。当在另一个类中使用Method.Invoke作为简单方法时,环境会随着表单中出现的异常源而变化。形式事件。我最终在Microsoft Support上发现了一些非常有趣的原因(“Windows窗体应用程序有一个顶级异常处理程序,允许程序在能够恢复的情况下继续运行”)

这也证实了Marc在将东西放入Load事件时提到的内容。唉。所以这一切的原因现在很明显

至于调试时运行良好的代码(与没有调试相反),我想我可以为此感谢JIT调试器@fluf向我指出,专门启用JIT调试器会产生与使用调试运行相同的结果@Marc Gravell,根据VS设置,这可能解释只有I和fluf才能复制。有更多的信息,但它不是一个生产修复


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

哪个框架?我不能在4.0上重新编程;也。。。为什么要执行异步开始/结束?这在Framework2.0上实现不了什么(但会让生活变得艰难)。异步开始/结束只是有一个异步进程,并在大型应用程序(在异步调用中调用对话框)之外重现问题。我重现了错误。net 2和vs2010只有在VSF外部运行exe时才会引发未经处理的异常。您可以通过将Jit调试添加到应用程序配置文件中来删除错误。我不知道为什么这样做可以解决问题,而且它是否真的可以解决问题,但会有所帮助。如果直接调用InvokeForm()会发生什么?结果相同。奇怪的是,在调试中运行时,我能够捕获异常!您是否尝试过在.NET2.0中回购?即使我将代码放在btn_单击中,也会得到相同的结果。我将代码放在表单_load中的唯一原因是为了测试应用程序。真正的应用程序从一个线程调用它(我放置异步调用的原因,但现在看到它不需要重现)。@MoSlo我的测试项目的目标确实是2.0。