下面的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"
}
}
答案 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;
}