天天看點

C#多線程編成之Async,Await(四)異常

  • 重新包裝任務失敗時産生的多個異常(《C# in depth page. 424〉)

  • 捕獲包含多個異常的AggregateException(《C# in depth page. 424〉)

  • 以熟悉的方式處理異步異常

static async Task MainAsync()
        {
            Task<string> task = ReadFileAsync("garbge file");
            try
            {
                string text = await task;//這裡使用await異常會從任務中解包,被catch到的就是IOException
                Console.WriteLine("File contents: {0}", text);
            }
            catch (IOException e)
            {
                Console.WriteLine("Caught IOException: {0}", e.Message);
            }

        }

     static void MainAsync()
        {
            Task<string> task = ReadFileAsync("garbge file");
            try
            {
                task.Wait();//如果直接等待,則會抓到這個AggregateException 
               // Console.WriteLine("File contents: {0}", text);
            }
            catch (AggregateException e)
            {
                Console.WriteLine("Caught IOException: {0}", e.Message);
            }

        }

        static async Task<string> ReadFileAsync(string filename)
        {
            Thread.Sleep(10 * 1000);
            using (var reader = File.OpenText(filename))
            {
                return await reader.ReadToEndAsync(); //異步操作
            }
        }
           
  • 異常方法中失效的參數驗證

static async Task MainAsync()
        {
            Task<int> task = ComputeLengthAsync(null);
            Console.WriteLine("Fetched the task"); //這個會被執行到
            try
            {
                int length = await task;//此時才能 Catch 到 ArgumentNullException 
            }
            catch (ArgumentNullException ex)
            {

            }
           // Console.WriteLine("Length: {0}", length);
        }
        static async Task<int> ComputeLengthAsync(string text)
        {
            if (text == null)
            {
                throw new ArgumentNullException("text");//雖然這個Exception很早就被抛出了,但是一直要到await那一句才會被catch到。
            }
            await Task.Delay(500);
            return text.Length;
        }
           
  • 将參數驗證從異步實作中分離出來

static async Task MainAsync()
        {
            Task<int> task = ComputeLengthAsync(null);
            Console.WriteLine("Fetched the task");
            int length = await task;
        }
    //以下方法本身不是一個異步方法,執行時使用的是正常的異步流
        static Task<int> ComputeLengthAsync(string text)
        {
            if (text == null)
            {
              //将參數驗證與實作分離
                throw new ArgumentNullException("text");
            }
            return ComputeLengthAsyncImp(text);
        }

        static async Task<int> ComputeLengthAsyncImp(string text)
        {
            await Task.Delay(10000);
            return text.Length;
        }
           
  • 通過抛出OperationCanceledException來建立一個取消的任務

static async Task ThrowCancellationException()
        {
            throw new OperationCanceledException();
        }


 Task task = ThrowCancellationException();
            Console.WriteLine(task.Status);//Canceled
           
  • 通過一個取消的延遲操作來取消異步方法

    static async Task DelayFor30Seconds(CancellationToken token)
            {
                Console.WriteLine("Waiting for 30 seconds...");
                await Task.Delay(TimeSpan.FromSeconds(30), token);//啟動一個異步的延遲操作
            }
    
     CancellationTokenSource soucre = new CancellationTokenSource();
                var task = DelayFor30Seconds(soucre.Token);//調用異步方法
                soucre.CancelAfter(TimeSpan.FromSeconds(1));//請求延遲的token取消工作
                Console.WriteLine("Initial status: {0}", task.Status);
    
                try
                {
                    task.Wait();//等待完成(同步)
                }
                catch (AggregateException e)
                {
                    Console.WriteLine("Caught {0}", e.InnerExceptions[0]);
                }
                Console.WriteLine("Final status: {0}", task.Status);//顯示任務狀态