這節來講一下如何捕獲Task的異常。
當Task運行中出現了異常,正常情況下我們在主線程的Try是捕獲不到的,而如果在Task內部寫try,出現了異常我們會完全不知道。下面就來介紹幾個主線程捕獲Task異常的方法。
阻塞線程式
我們可以使用Wait(),WaitAny(),WaitAll()來捕獲Task的異常,詳見下圖:

捕獲Task異常,准確來說要用AggregateException類,右邊是運行結果,成功捕獲到了異常信息,其它兩個等待也是類似的用法,不熟悉的小伙伴可以參見前文:等待多個異步任務的方法。
在等待多個Task異常時,可以訪問異常對象的InnerExceptions屬性來遍歷所有的異常:

上述異常捕獲的解決方案,因為涉及到了等待,所以會阻塞主線程,並且如果異常發生在等待之前,同樣是不能捕獲到,所以這種方式,雖然簡單,但是使用場景並不多。
異步式
我們知道Task有個ContinueWith方法,它會在Task完成后繼續異步執行傳入的委托,我們可以通過這個方法實現異常捕獲,請看如下代碼:

因為是異步執行,所以這樣不會阻塞主線程。
事件式
事件式的思路是在主線程中定義事件,在Task中通過觸發事件的形式讓主線程捕獲到異常,請看代碼:
首先定義一個事件參數:
internal class TaskExceptionEventArgs:EventArgs { /// <summary> /// 存放Task引發的異常對象 /// </summary> public AggregateException AggregateException { get; set; } }
主代碼如下:
class Program { private static event EventHandler<TaskExceptionEventArgs> taskExceptionEventHandler; static void Main(string[] args) { //為事件添加事件處理器 taskExceptionEventHandler = (sender, aeArgs) => { Console.WriteLine(aeArgs.AggregateException.Message); }; Task.Run(async () => { await Task.Delay(2 * 1000); try { throw new AggregateException("內部異常1"); } catch (AggregateException ex) { //觸發事件,並傳入參數 taskExceptionEventHandler.Invoke(null, new TaskExceptionEventArgs { AggregateException = ex }); } }); } }
這樣用法很靈活,而且拿到的是最直接的異常對象,並且不用等待Task執行完畢。

