为什么内部exception到达ThreadException处理程序而不是实际抛出的exception?
在抛出exception并在Application.ThreadException
事件处理程序中捕获它们时,我看到了一些奇怪的行为。
基本上,下面的示例中发生的是在BackgroundWorker
的DoWork
事件处理程序中抛出exception。 RunWorkerCompleted
事件处理程序重新抛出一个新exception,原始exception作为内部exception。
为什么内部exception出现在ThreadException
事件处理程序中而不是抛出的实际exception? 如果我在RunWorkerCompleted
事件处理程序中没有提供内部exception,则会显示正确的exception。
using System; using System.Windows.Forms; using System.ComponentModel; namespace WierdExceptionApp { class WierdExceptionForm : Form { BackgroundWorker worker = new BackgroundWorker(); public WierdExceptionForm() { worker.DoWork += new DoWorkEventHandler(worker_DoWork); worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted); worker.RunWorkerAsync(); } void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { if (e.Error != null) { throw new Exception("worker_RunWorkerCompleted", e.Error); } } void worker_DoWork(object sender, DoWorkEventArgs e) { throw new Exception("worker_DoWork"); } [STAThread] static void Main() { Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException); Application.Run(new WierdExceptionForm()); } static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e) { MessageBox.Show(e.Exception.Message); } } }
RunWorkerCompleted事件由WW管道从BGW线程封送到UI线程,使得Control.Invoke()工作。 本质上,有一个队列,其中包含由消息循环清空的委托。 执行此操作的代码Control.InvokeMarshaledCallbacks(),您将在调用堆栈上看到它,有一个catch(Exception)子句来捕获未处理的exception。 该子句调用Application.OnThreadException,传递Exception.GetBaseException()的值。
那么,这就解释了为什么你只看到内部exception。 为什么这样做有点不清楚。 可能会切断UI线程中代码的堆栈帧,否则会很困惑,因为真正的exception来自后台线程。
if (e.Error != null) { throw new Exception("worker_RunWorkerCompleted", new Exception("Inner", new Exception("Inner inner"))); }
你最终会得到“内在的内在”。 看来这是Application_ThreadException方法的行为来查看最内层的exception。