并发编程并发编程并发编程 --- 异步方法的异常处理
Fantasy-ke引言
现在模拟一个异步方法抛出了异常:
| 12
 3
 4
 5
 
 | public static async Task ThrowAfter(int ms, string message){
 await Task.Delay(ms);
 throw new Exception(message);
 }
 
 | 
思考一下, DontHandle() 方法是否能够捕获到异常?
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 
 | public static void DontHandle(){
 try
 {
 ThrowAfter(1000, "first");
 }
 catch (Exception ex)
 {
 Console.WriteLine(ex.Message);
 }
 
 }
 
 | 
答案是:不会捕获到异常!
因为 DontHandle() 方法在 ThrowAfter() 方法抛出异常之前,就已经执行完毕。
异步方法的异常处理
那么上述代码怎么才能捕获到异常呢?
若想要捕获异常则必须通过 await 关键字等待 ThrowAfter() 方法执行完成。
将上文中的代码段进行修改:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 
 | public static async void HandleoOnError(){
 try
 {
 await ThrowAfter(1000, "first");
 }
 catch (Exception ex)
 {
 Console.WriteLine(ex.Message);
 }
 }
 
 | 
结果就会输出:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 
 | public static async void StartTwoTasks(){
 try
 {
 await ThrowAfter(1000, "first");
 await ThrowAfter(1000, "second");
 Console.WriteLine("StartTwoTasks is Complate");
 }
 catch (Exception ex)
 {
 Console.WriteLine(ex.Message);
 }
 }
 
 | 
思考一下输出是什么?
答案是:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 
 | public static async void StartTwoTasksParallel(){
 try
 {
 Task t1 = ThrowAfter(1000, "first");
 Console.WriteLine("t1 is Complate");
 Task t2 = ThrowAfter(1000, "second");
 Console.WriteLine("t2 is Complate");
 await Task.WhenAll(t2, t1);
 }
 catch (Exception ex)
 {
 Console.WriteLine(ex.Message);
 }
 }
 
 | 
输出:
| 12
 3
 
 | is Complatet2 is Complate
 second
 
 | 
从输出可以看出来,使用 WhenAll() 方法,两个任务都是执行完成的,但是,捕获异常只能捕获 WhenAll()方法参数中,排在最前面的,且第一个抛出异常的任务的消息,
上述方式有缺陷,只能抛出一个异常的任务的消息,可以将上面的方式再进化一下,如下代码:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 
 | public static async void StartTwoTasksParallelEx(){
 Task t1 = null;
 Task t2 = null;
 try
 {
 t1 = ThrowAfter(1000, "first");
 t2 = ThrowAfter(1000, "second");
 await Task.WhenAll(t2, t1);
 
 }
 catch (Exception ex)
 {
 if (t1.IsFaulted)
 {
 Console.WriteLine(t1.Exception.InnerException.Message);
 }
 
 if (t2.IsFaulted)
 {
 Console.WriteLine(t2.Exception.InnerException.Message);
 }
 }
 }
 
 | 
输出:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 
 | public static async void StartTwoTasksParallelEx2(){
 Task t3 = null;
 try
 {
 Task t1 = ThrowAfter(1000, "first");
 Task t2 = ThrowAfter(1000, "second");
 await (t3 = Task.WhenAll(t2, t1));
 
 }
 catch (Exception ex)
 {
 foreach (var item in t3.Exception.InnerExceptions)
 {
 Console.WriteLine("InnerException:" + item.Message);
 }
 }
 }
 
 | 
输出: