Control.Invoke展开外部异常并传播内部异常

时间:2015-01-20 20:26:19

标签: c# winforms invoke

下面的MessageBox.Show电话会显示“内部”。这是一个错误吗?

private void Throw()
{
    Invoke(new Action(() =>
    {
        throw new Exception("Outer", new Exception("Inner"));
    }));
}

private void button1_Click(object sender, EventArgs e)
{
    try
    {
        Throw();
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message); // Shows "Inner"
    }
}

2 个答案:

答案 0 :(得分:5)

我查看了System.Windows.Forms.Control的参考来源,处理Invoke的代码如下所示:

try {
    InvokeMarshaledCallback(current);
}
catch (Exception t) {
    current.exception = t.GetBaseException();
}

GetBaseException

public virtual Exception GetBaseException() 
{
    Exception inner = InnerException;
    Exception back = this;

    while (inner != null) {
        back = inner;
        inner = inner.InnerException;
    }

    return back;
}

显然,这就像设计一样。来源中的评论没有解释为什么他们这样做。

编辑:一些现在已经消失的网站声称这条评论来自微软的一个人:

  

根据记录中的winform确认,我们的分析是   正确的根本原因和这种行为是有意的。原因是   防止用户看到太多的Windows.Forms内部机制。   这是因为winform的默认错误对话框还利用Application.ThreadException来显示异常详细信息。 .Net Winform   团队修剪其他异常信息,以便默认错误   对话框不会向最终用户显示所有细节。

     

此外,一些MSFT已经建议改变这种行为。但是,.Net   Winform团队认为改变抛出的异常是一个突破   更改,因此WinForms将继续向Application.ThreadException处理程序发送最内层的异常。

答案 1 :(得分:0)

OP似乎对解决方法不感兴趣。无论如何,这是我的:

public static object InvokeCorrectly(this Control control, Delegate method, params object[] args) {
    Exception failure = null;
    var result = control.Invoke(new Func<object>(() => {
        try {
            return method.DynamicInvoke(args);
        } catch (TargetInvocationException ex) {
            failure = ex.InnerException;
            return default;
        }
    }));
    if (failure != null) {
        throw failure;
    }
    return result;
}
相关问题