2012-03-30 52 views
6

我已經閱讀了很多關於如何處理TPL中的異常但不太明白的地方。處理Tpl中的異常

讓我們這個例子代碼:

var task1 = new Task(() => { throw new Exception("Throw 1"); }); 
var task2 = task1.ContinueWith(t => Console.WriteLine("Catch 1:{0}", t.Exception.Message), 
           TaskContinuationOptions.OnlyOnFaulted); 
var task3 = task2.ContinueWith(t => Console.WriteLine("Continuation")); 

task1.Start(); 
try { 
    task1.Wait(); 
} 
catch (Exception ex) { 
    Console.WriteLine("Wait Exception: {0}", ex.Message); 
} 

我預計打印

Catch 1 
Continuation 

,但我得到

Catch 1 
Continuation 
Wait Exception 

這意味着異常仍然被認爲是未處理的當任務完成並且任務終結器將最終拆除應用程序。

如何處理延續內部的異常,使終結器不會拋出?與此同時,我希望任務保持在故障狀態,因此將任務包裝在try/catch中將不起作用。


背景是,我想要實現的異步事件模式作爲指定here但錯誤處理。我完整的代碼看起來像這樣

public IAsyncResult Begin(AsyncCallback callback, object state, Action action) { 
    var task1 = new Task(action); 
    var task2 = task1.ContinueWith(t => HandleException(t.Exception), 
            TaskContinuationOptions.OnlyOnFaulted); 
    if (callback != null) { 
     var task3 = task2.ContinueWith(t => callback(t), 
             TaskScheduler.FromCurrentSynchronizationContext()); 
     var task4 = task3.ContinueWith(t => HandleException(t.Exception), 
             TaskContinuationOptions.OnlyOnFaulted); 
    } 

    task1.Start(); 

    return task; 
} 
+0

我想在繼續嘗試中調用't.Wait()'並忽略異常。但是這是行不通的,因爲繼續可能會在另一個Wait()拋出之後執行。 – svick 2012-03-30 20:39:35

回答

3

你做你的等待上失敗的任務,如果你看過documentation on Task.Wait仔細,你會看到,等待將重新拋出異常在這種情況下。

但是,如果您在task3上等待,則應該按預期工作。

當然,你應該記住這一點:

當您使用OnlyOnFaulted選項,可以保證的是,在前期的 異常屬性不爲null。您可以使用該 屬性來捕獲異常並查看哪個異常導致 任務發生故障。如果您不訪問「異常」屬性,則 異常將處於未處理狀態。另外,如果您嘗試訪問已取消或發生故障的任務的結果 屬性,則會引發新的異常。

(參考here

最後又一個好來源How to handle exceptions thrown by tasks

我希望這有助於。

+1

我想我明白了。即使我訪問.Exception屬性,Wait總是會導致異常。但是,訪問.Exception將異常更改爲不「未處理」,因此任務終結器不會拋出。一個快速測試似乎證實了這一點。謝謝 – adrianm 2012-03-30 22:26:01