天天看点

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);//显示任务状态