2010-04-12 74 views
7

我不做很多Windows GUI編程,所以這對於更熟悉WinForms的人來說可能都是我的常識。不幸的是我一直沒能找到任何資源來解釋這個問題,我今天在調試過程中遇到過。Control.EndInvoke重置調用堆棧異常

如果我們在異步委託上調用EndInvoke。在重新拋出方法的執行期間,我們將得到拋出的任何異常。調用堆棧將反映異常的原始來源。但是,如果我們在Windows.Forms.Control上執行類似操作,則Control.EndInvoke的實現將重置調用堆棧。這可以通過簡單的測試或通過查看Reflector中的代碼來觀察。從EndInvoke會相關的代碼摘錄是在這裏:

if (entry.exception != null) 
{ 
    throw entry.exception; 
} 

我明白,開始/ EndInvoke會在控制和異步委託是不同的,但我本來期望在Control.EndInvoke類似的行爲。

是否有任何理由控制不會做任何異步委託做保存原始調用堆棧?

回答

1

我不知道真正的原因,但我可以猜測,異步委託類似於RPC,而控制委託可能基於Win32消息發送。所以不同的技術對此功能的影響可能不盡相同。異步委託可以從所有遠程代碼中受益,開發人員可以編寫這些代碼來在不同的進程或計算機之間傳輸異常調用堆棧,而控制代理將在同一進程中使用PostMessage模擬RPC。不同的團隊,不同的代碼。

1

還要注意Control.EndInvoke是框架中爲數不多的Managed EndInvokes(因此您可以在Reflector中看到代碼)。他們可能應該有一個非管理員助手,拋出原來的堆棧。

事實上,我認爲這是唯一管理EndInvoke,但也有其他管理End*程序與IAsyncResult參數。我沒有檢查過所有這些,但似乎所有我已經審查的人只是拋出異常,或者有效地使用Stephen Cleary的轉移解決方案來使用.NET 4的GetWaiter.GetResult,該解決方案確實有一些託管和非託管惡意設法嘗試獲取堆棧恢復異常。

1

我不知道爲什麼控制不這樣做(也許只是一個監督),但你可以通過計劃任務的UI形式工作,它圍繞在.NET 4.0中:

private BackgroundWorker bgw; 
    private TaskFactory uiTaskFactory; 

    private void Form1_Load(object sender, EventArgs e) 
    { 
     this.uiTaskFactory = new TaskFactory(TaskScheduler.FromCurrentSynchronizationContext()); 
     this.bgw = new BackgroundWorker(); 
     this.bgw.DoWork += bgw_DoWork; 
     this.bgw.RunWorkerAsync(); 
    } 

    void bgw_DoWork(object sender, DoWorkEventArgs e) 
    { 
     var task = this.uiTaskFactory.StartNew(this.OuterTaskFunction); 
     try 
     { 
      task.Wait(); 
     } 
     catch (Exception ex) 
     { 
      // Note: Full stack trace preserved 
      MessageBox.Show(ex.InnerException.ToString()); 
     } 
    } 

    void OuterTaskFunction() 
    { 
     this.InnerTaskFunction(); 
    } 

    void InnerTaskFunction() 
    { 
     throw new InvalidOperationException("Blah."); 
    } 
-3

我沒有閱讀您的消息100%,所以我不知道這是否有幫助,或者我只是說明顯的事情,但是當發現異常並且您寫入時

「throw iAmAnCaughtExceptionInstance;」

調用堆棧不會被保存,你應該只寫

「扔」;

,然後調用堆棧被保存

+1

我知道,但因爲我不是誰實施了一個Windows.Forms.Control它的幫助不大。 – 2010-05-13 22:09:44