c# 高级编程 15章321页 【异步编程】【错误处理】

181 阅读1分钟

示例:一个扔异常的异步方法

        static async Task ThrowAfter(int ms, string message)
        {
            await Task.Delay(ms);
            throw new Exception(message);
        }

示例:不await,捕获不到异常

  • 没有await 异步方法ThrowAfter()
  • ThrowAfter()抛出异常之前,其调用者,DontHandle() 已经执行完毕
  • 所以try-catch,也捕获不到异常
        private static void DontHandle()
        {
            try
            {
                #pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
                ThrowAfter(200, "first");
                #pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
                              // Exception is not caught because the exception is assigned to the task which is not awaited
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }

示例:await,捕获异常

  • 能捕获异常
        private static async void HandleOneError()
        {
            try
            {
                await ThrowAfter(2000, "first");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"handled {ex.Message}");
            }
        }

示例:多个异步方法都会扔异常,但这么实现,有的不执行

  • 第二个ThrowAfter()方法没执行
        private static async void StartTwoTasks()
        {
            try
            {
                await ThrowAfter(2000, "first");
                await ThrowAfter(1000, "second"); // the second call is not invoked because the first method throws an exception
            }
            catch (Exception ex)
            {
                Console.WriteLine($"handled {ex.Message}");
            }
        }

示例: 多个异步方法都会扔异常,这么实现,所有异步方法都能执行,但只能捕获第一个异步方法的异常

  • 通过await Task.WhenAll(t1, t2);
        private async static void StartTwoTasksParallel()
        {
            Task t1 = null;
            try
            {
                t1 = ThrowAfter(2000, "first");
                Task t2 = ThrowAfter(1000, "second");
                await Task.WhenAll(t1, t2);
            }
            catch (Exception ex)
            {
                // just display the exception information of the first task that is awaited within WhenAll
                Console.WriteLine($"handled {ex.Message}");
            }
        }

示例:多个异步方法都会扔异常,这么实现,所有异步方法都能执行,并且能观察到所有异步方法抛出的异常

  • 通过TaskException.InnerExceptions可以看到两个ThrowAfter()扔的异常
  • 另外还可以通过Task的属性IsFaulted来检查,是否出错。如果任务有异常,IsFaulted会是true
        private static async void ShowAggregatedException()
        {
            Task taskResult = null;
            try
            {
                Task t1 = ThrowAfter(2000, "first");
                Task t2 = ThrowAfter(1000, "second");
                await (taskResult = Task.WhenAll(t1, t2));
            }
            catch (Exception ex)
            {
                // just display the exception information of the first task that is awaited within WhenAll
                Console.WriteLine($"handled {ex.Message}");
                foreach (var ex1 in taskResult.Exception.InnerExceptions)
                {
                    Console.WriteLine($"inner exception {ex1.Message} from task {ex1.Source}");
                }
            }
        }