C# 異步編程Task整理(二)異常捕捉


一、在任務並行庫中,如果對任務運行Wait、WaitAny、WaitAll等方法,或者求Result屬性,都能捕獲到AggregateException異常。

可以將AggregateException異常看做是任務並行庫編程中最上層的異常。

在任務中捕獲的異常,最終都應該包裝到AggregateException中。一個任務並行庫異常的簡單處理示例如下:

static void TestTwo()
{
    Task t1= Task.Factory.StartNew(() => {

        throw new Exception("執行失敗");
    });
    try
    {
        //主線程等待,可以 捕捉異常
        t1.Wait();
    }
    catch (AggregateException ex)
    {
        foreach (var item in ex.InnerExceptions)
        {
            Console.WriteLine("異常類型:{0}{1}來自:  {2} {3} 異常內容:{4} ", item.GetType(),  
        Environment.NewLine, item.Source,  
        Environment.NewLine, item.Message);
        }
        Console.Write(ex.Message);
    }
}

二、方式2使用主線程委托,這種方式比較推薦

 在這個例子中,我們聲明了一個委托AggregateExceptionCatchHandler,它接受兩個參數,一個是事件的通知者;另一個是事件變量AggregateExceptionArgs。AggregateExceptionArgs是為了包裝異常而新建的一個類型。在主線程中,我們為事件AggregateExceptionCatched分配了事件處理方法Program_AggregateExceptionCatched,當任務Task捕獲到異常時,代碼引發事件。

這種方式完全沒有阻滯主線程。如果是在Winform或WPF窗體程序中,要在事件處理方法中處理UI界面,還可以將異常信息交給窗體的線程模型去處理。所以,最終建議大家采用事件通知的模型處理Task中的異常。

//定義AggregateException 的事件委托
static event EventHandler<AggregateExceptionArgs> AggregateExceptionCatched;
static void TestThree()
{
    AggregateExceptionCatched += new EventHandler<AggregateExceptionArgs>(Program_AggregateExceptionCatched);

    Task t1 = new Task(() =>
    {
        try
        {
            throw new InvalidOperationException("任務並行編碼 中產生未知錯誤");
        }
        catch (Exception ex)
        {
            AggregateExceptionArgs args = new AggregateExceptionArgs()
            {
                AggregateException = new AggregateException(ex)
            };
            //使用主線程委托代理,處理子線程 異常
            //這種方式沒有阻塞 主線程或其他線程
            AggregateExceptionCatched?.Invoke(null, args);
        }
    });
    t1.Start();
}
static void Program_AggregateExceptionCatched(object sender, AggregateExceptionArgs e)
{
    foreach (var item in e.AggregateException.InnerExceptions)
    {
        Console.WriteLine("異常類型:{0}{1}來自:{2}{3}異常內容:{4}",
            item.GetType(), Environment.NewLine, item.Source,
            Environment.NewLine, item.Message);
    }
}
//定義異常參數處理
public class AggregateExceptionArgs : EventArgs
{
    public AggregateException AggregateException { get; set; }
}

三、TaskScheduler.UnobservedTaskException

注意 任務調度器TaskScheduler提供了這樣一個功能,它有一個靜態事件用於處理未捕獲到的異常。一般不建議這樣使用,因為事件回調是在進行垃圾回收的時候才發生的。

static void TestFourth()
{
    TaskScheduler.UnobservedTaskException += new EventHandler<UnobservedTaskExceptionEventArgs>(TaskScheduler_UnobservedTaskException);

    Task t1 = new Task(() =>
    {
        throw new Exception("任務並行編碼中 產生 未知錯誤");
    });
    t1.Start();
    Console.ReadKey();//主線程等待
    t1 = null;
    //GC.Collect(0); //只有在回收t1對象 的時候才會觸發UnobservedTaskException
    Console.WriteLine("主線程馬上結束");
    Console.Read();
}
static void TaskScheduler_UnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e)
{
    foreach (Exception item in e.Exception.InnerExceptions)
    {
        Console.WriteLine("異常類型:{0}{1}來自:{2}{3}異常內容:{4}",
            item.GetType(), Environment.NewLine, item.Source,
            Environment.NewLine, item.Message);
    }
    //將異常標識為已經觀察到  
    e.SetObserved();
}

更多 :

C# 異步編程Task整理(一)

C# Process獲取當前進程信息

C# ApartmentState 枚舉,指定線程單元狀態


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM