2008-12-07 21 views
13

在拋出異常並將它們捕獲到Application.ThreadException事件處理程序中時,我看到一些奇怪的行爲。爲什麼內部異常到達ThreadException處理程序而不是實際拋出的異常?

基本上,下面示例中發生的情況是的DoWork事件處理程序中引發了異常。 RunWorkerCompleted事件處理程序將原始內容作爲內部異常重新引發新的異常。

爲什麼內部異常顯示在ThreadException事件處理程序中,而不是引發的急性異常?如果我沒有在RunWorkerCompleted事件處理程序中提供內部異常,則會顯示正確的異常。

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); 
     } 
    } 
} 
+0

令人震驚的;這一直困擾我多年,沒有我意識到這一點。我偶爾會看到這些偶爾出現的錯誤報告,說明我可以發誓處理的事情。他們非常罕見,沒有花太多時間去研究它們,但最終它開始發生了一些重要的事情,我意識到這個例外正在發生變化。 WTF? – 2011-04-23 03:57:14

回答

9

RunWorkerCompleted事件通過使Control.Invoke()工作的WF管道從BGW線程編組到UI線程。本質上,有一個由消息循環清空的委託隊列。執行此操作的代碼Control.InvokeMarshaledCallbacks()將在調用堆棧中看到它,它有一個catch(Exception)子句來捕獲未處理的異常。該子句調用Application.OnThreadException,傳遞Exception.GetBaseException()的值。

那麼,這就解釋了爲什麼你只能看到內部的異常。爲什麼這樣做是有點不清楚。可能會切斷UI線程中代碼的堆棧幀,否則這些幀會非常混亂,因爲真正的異常來自後臺線程。

+8

然而,*微軟絕對不會修復WinForms中的另一個*錯誤! – Joshua 2008-12-07 22:12:06

0
 if (e.Error != null) 
     { 
      throw new Exception("worker_RunWorkerCompleted", new Exception("Inner", new Exception("Inner inner"))); 
     } 

你得到底 「裏面的內」。看起來,這是Application_ThreadException方法查看最內部異常的行爲。

相關問題