2013-07-30 77 views
1

請遵守這個簡單的代碼:如何讓異常從異步方法傳播堆棧? (不能使用異步或等待關鍵字)

try 
    { 
    var t = Task.Factory.StartNew<bool>(() => { throw new Exception("aaa"); }); 
    t.ContinueWith(_ => {}, TaskContinuationOptions.OnlyOnRanToCompletion).Wait(); 
    } 
    catch (Exception exc) 
    { 
    Debug.WriteLine(exc); 
    } 

我假設,如果t有關聯的異常,那麼這個異常會被重新拋出的是Wait()。然而,只有延續成功的存在似乎改變了這種行爲。拋出什麼是一個「任務被取消」的例外。

事實上,就Wait()之前鏈接一個TaskContinuationOptions.NotOnRanToCompletion完成處理表明,傳遞給它的任務不是故障,而是取消:

t.ContinueWith(_ => { }, TaskContinuationOptions.OnlyOnRanToCompletion) 
.ContinueWith(t2 => Debug.Assert(t2.IsCanceled), TaskContinuationOptions.NotOnRanToCompletion) 
.Wait(); 

這是所有有點怪。這意味着,我不能只鏈接我的快樂路徑完成處理程序,讓任何異常只是傳播到等待線程的最終會合。

我在這裏錯過了什麼?

注意

我僅限於.NET 4.0,所以沒有awaitasync關鍵字。

+4

如果你不知道,你可以使用異步的.NET 4.0/AWAIT http://blogs.msdn.com/b/bclteam/archive/2013/04/17/microsoft-bcl -async-is-now-stable.aspx –

+0

@zespri:非常好! –

+0

有趣。以下是一篇指導性文章:http://blogs.msdn.com/b/bclteam/archive/2012/10/22/using-async-await-without-net-framework-4-5.aspx – StriplingWarrior

回答

2

我在這裏錯過了什麼?

您缺少.NET 4.5。如果沒有awaitasync關鍵字,任務仍然有用,但是如果您想要討論的是「開心路徑」行爲, 則需要升級 (請參見下面的更新)。

因爲任務是比標準運行通過代碼更加複雜,因爲他們可以以各種方式連接在一起,你需要直接從Task索要例外,而不是通過調用拋出的異常.Wait()

var t = Task.Factory.StartNew<bool>(() => { throw new Exception("aaa"); }); 
    try 
    { 
    t.ContinueWith(_ => {}, TaskContinuationOptions.OnlyOnRanToCompletion) 
     .Wait(); 
    } 
    catch (AggregateException exc) 
    { 
    Debug.WriteLine(exc.InnerExceptions[0]);// "A task was canceled" 
    Debug.WriteLine(t.Exception.InnerExceptions[0]);// "aaa" 
    } 

更新:如果您使用Visual Studio 2012,看來you can使用asyncawait關鍵字而不升級到4.5。感謝@zespri指出了這一點。

更新2:如果你想趕上,並在頂層記錄相應的例外,只要包裝在try/catch塊你.Wait()方法的習慣,換了給定異常。

try 
{ 
    t.Wait(); 
} 
catch (AggregateException exc) 
{ 
    throw new Exception("Task Foo failed to complete", t.Exception); 
} 
+0

不幸的是,'' t'不在實際應用中的捕手範圍內。 – mark

+0

@mark:考慮問自己爲什麼不。調用'.Wait()'的代碼將在try/catch塊中包裝該調用並記錄或包裝相應的異常似乎是合理的,因爲這是知道它正在等待異步任務的代碼。如果這看起來不適合你,也許該方法本身需要返回一個Task,並讓調用方法執行'.Wait()'。 – StriplingWarrior