1. 程式人生 > >C# 異步編程Task整理(二)異常捕捉

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

如果 console url 完全 list 標識 異步 通知 註意

一、在任務並行庫中,如果對任務運行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 枚舉,指定線程單元狀態

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