Task異常捕獲的方式

Charles_Su發表於2021-06-30

    這節來講一下如果捕獲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執行完畢。

 

相關文章