2011-09-27 50 views
3

我有重新拋出異常的代碼。重新拋出任務異常(TPL)失去堆棧跟蹤

當我稍後從task.Exception中讀取異常時,它的堆棧跟蹤指向我重新拋出異常的位置(第n行而不是第m行,如我所料)。

這是爲什麼? TPL中的錯誤或更可能是我忽視的東西。

由於我的解決方法是我可以將異常作爲內部異常包裝在新的異常中。

internal class Program 
{ 
    private static void Main(string[] args) 
    { 
     Task.Factory.StartNew(TaskMethod).ContinueWith(t => Console.WriteLine(t.Exception.InnerException)); 
     Console.Read(); 
    } 

    private static void TaskMethod() 
    { 
     try 
     { 
line m:  throw new Exception("Todo"); 
     } 
     catch (Exception) 
     { 
line n:  throw; 
     } 
    } 
} 
+1

替換行號問題的'throw'是相當有名的。有一篇[博客文章](http://weblogs.asp.net/fmarguerie/archive/2008/01/02/rethrowing-exceptions-and-preserving-the-full-call-stack-trace.aspx)討論了一種可能解決方法,但我沒有使用它自己。 –

回答

3

不幸的是,由於TPL存儲異常的方式,直到任務完成執行,原始堆棧跟蹤丟失。在LINQPad中運行你的示例代碼表明這個異常拋出在at System.Threading.Tasks.Task.Execute(),這顯然是不正確的。

爲粗製的解決方法,你可以存儲原來的堆棧跟蹤(它是一個簡單的字符串)的原始異常的Data屬性,你就可以訪問它,那麼:

private static void TaskMethod() 
{ 
    try 
    {   
     throw new Exception("Todo"); 
    } 
    catch (Exception ex) 
    { 
     ex.Data["OriginalStackTrace"] = ex.StackTrace; 
     throw; 
    } 
} 

那麼你就必須存儲在OriginalStackTrace價值Data字典的原始堆棧跟蹤:

這不是你想要的,但我希望它有幫助。

+0

現在我知道這就是它的方式。我想我只是將異常像拋出新異常(「See inner exception」,e); – Karsten