我有一个针对 Application.ThreadException
的处理程序,但我发现异常并不总是被正确地传递给它。具体来说,如果我从 BeginInvoke
回调中抛出具有内部异常的异常,则我的 ThreadException
处理程序无法获得外部异常--它只能获取内部异常。
示例代码:
public Form1()
{
InitializeComponent();
Application.ThreadException += (sender, e) =>
MessageBox.Show(e.Exception.ToString());
}
private void button1_Click(object sender, EventArgs e)
{
var inner = new Exception("Inner");
var outer = new Exception("Outer", inner);
//throw outer;
BeginInvoke(new Action(() => { throw outer; }));
}
如果我取消注释 throw outer;
这一行并点击按钮,那么消息框会显示外部异常(以及它的内部异常):
但如果System.Exception: Outer ---> System.Exception: Inner
--- 内部异常堆栈跟踪的结尾 ---
在 WindowsFormsApplication1.Form1.button1_Click(Object sender, EventArgs e) 位置 C:\svn\trunk\Code Base\Source.NET\WindowsFormsApplication1\Form1.cs 中: 行 55
在 System.Windows.Forms.Control.OnClick(EventArgs e)
在 System.Windows.Forms.Button.OnClick(EventArgs e)
在 System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent)
在 System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
在 System.Windows.Forms.Control.WndProc(Message& m)
在 System.Windows.Forms.ButtonBase.WndProc(Message& m)
在 System.Windows.Forms.Button.WndProc(Message& m)
在 System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
在 System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
在 System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
throw outer;
在一个 BeginInvoke
调用内部,就像上面的代码一样,那么 ThreadException
处理程序仅会得到内部异常。在调用 ThreadException
之前,外部异常被剥离,我只能得到以下信息:
(这里没有调用堆栈,因为System.Exception: Inner
inner
从未被抛出。在一个更现实的示例中,当我捕获一个异常并包装它以重新抛出时,就会有一个调用堆栈。)如果我使用
SynchronizationContext.Current.Post
代替 BeginInvoke
,那么外部异常将被剥离,并且 ThreadException
处理程序仅会得到内部异常。我尝试在外面包装更多层异常,以防止它仅仅剥离最外层的异常,但是没有任何帮助:显然某个地方有一个循环执行类似
while (e.InnerException != null) e = e.InnerException;
的操作。我使用
BeginInvoke
是因为我的代码需要抛出一个未处理的异常,以便立即由 ThreadException
处理,但是此代码位于调用堆栈的较高位置的 catch
块内(具体来说,它位于 Task
的操作内部,而 Task
将捕获异常并阻止其传播)。我正在尝试使用 BeginInvoke
将 throw
延迟到下一次消息在消息循环中处理时,此时我不再在那个 catch
中。我并没有固定使用 BeginInvoke
的解决方案;我只想抛出未处理的异常。如何使一个异常(包括它的内部异常)在我处于别人的
catch-all
内部时达到 ThreadException
?(由于程序集依赖项,我无法直接调用我的 ThreadException
处理程序方法,因为处理程序是被 EXE 的启动代码钩住的,而我的当前问题在较低层的 DLL 中。)
Exception.GetBaseException()
的意义是什么?它并没有提供任何好处,只会减少在显示的未处理异常对话框中看到的上下文/堆栈数量,并防止任何ThreadException
处理程序看到实际抛出的(外部)异常。既然这是有意为之的,那么人们试图通过这样做解决什么问题呢?难道不能修复吗? - binki