Try...Catch....Finally
一、异步方法中的异常:
异步方法:异步方法有async来修饰,通常包含一个或多个await表达式,await表达式应用于Task或者Task<TResult>类型的操作, await表达式不能出现在catch块或finally块中。
1)当程序运行到async方法中的await表达式时,程序会挂起直到await完成。
1.await等待的任务发生未经处理的异常时,会抛出异常
2.await等待的任务被取消时,会抛出OperationCancaledException
想要捕捉这些异常,await表达式放于try块中,紧接着catch捕获。
1 public async Task DoSomethingAsync() 2 3 { 4 5 Task<string> theTask = DelayAsync(); 6 7 try 8 9 { 10 11 string result = await theTask; 12 13 Console.WriteLine("Result: " + result); 14 15 } 16 17 catch (Exception ex) 18 19 { 20 21 Console.WriteLine("Exception Message: " + ex.Message); 22 23 } 24 25 Console.WriteLine("Task IsCanceled: " + theTask.IsCanceled); 26 27 Console.WriteLine("Task IsFaulted: " + theTask.IsFaulted); 28 29 if (theTask.Exception != null) 30 31 { 32 33 Console.WriteLine("Task Exception Message: " 34 35 + theTask.Exception.Message); 36 37 Console.WriteLine("Task Inner Exception Message: " 38 39 + theTask.Exception.InnerException.Message); 40 41 } 42 43 } 44 45 private async Task<string> DelayAsync() 46 47 { 48 49 await Task.Delay(100); 50 51 52 53 // Uncomment each of the following lines to 54 55 // demonstrate exception handling. 56 57 58 59 //throw new OperationCanceledException("canceled"); 60 61 //throw new Exception("Something happened."); 62 63 return "Done"; 64 65 }
未经处理的异常抛出:
任务被取消时抛出OperationCanceledException:
2)Task.WhenAll返回的异常:
1 public async Task DoMultipleAsync() 2 3 { 4 5 Task theTask1 = ExcAsync(info: "First Task"); 6 7 Task theTask2 = ExcAsync(info: "Second Task"); 8 9 Task theTask3 = ExcAsync(info: "Third Task"); 10 11 12 13 Task allTasks = Task.WhenAll(theTask1, theTask2, theTask3); 14 15 try 16 17 { 18 19 await allTasks; 20 21 } 22 23 catch (Exception ex) 24 25 { 26 27 Console.WriteLine("Exception: " + ex.Message); 28 29 Console.WriteLine("Task IsFaulted: " + allTasks.IsFaulted); 30 31 foreach (var inEx in allTasks.Exception.InnerExceptions) 32 33 { 34 35 Console.WriteLine("Task Inner Exception: " + inEx.Message); 36 37 } 38 39 } 40 41 } 42 43 private async Task ExcAsync(string info) 44 45 { 46 47 await Task.Delay(100); 48 49 throw new Exception("Error-" + info); 50 51 }
Catch块中通过Exception.InnerExceptions 迭代出每个任务的异常
二、.finally:通过finally块,我们可以释放try块中分配的任何资源,通常控制流离开try块后就进入finally,但是对于break,continue,goto,return或者异常的向外传播会导致控制流的变化。
在经处理的异常里,finally块一定会执行,而在未经处理的异常里,它依赖于操作系统是否触发异常展开操作。通常未经处理的异常会导致应用程序的终结,这时finally块中的代码运行与否已经不重要了,若是一定要运行finally块中的代码,那么一种解决方案是加catch块捕捉异常,并在catch块中进行处理。另一种就是在调用含有try..finally块方法的方法中或者调用栈中的任何方法中进行捕捉,这样finally块就能得到调用。
1 static void Main(string[] args) 2 3 { 4 5 try 6 7 { 8 9 // TryCast produces an unhandled exception. 10 11 TryCast(); 12 13 } 14 15 catch (Exception ex) 16 17 { 18 19 // Catch the exception that is unhandled in TryCast. 20 21 Console.WriteLine 22 23 ("Catching the {0} exception triggers the finally block.", 24 25 ex.GetType()); 26 27 28 29 // Restore the original unhandled exception. You might not 30 31 // know what exception to expect, or how to handle it, so pass 32 33 // it on. 34 35 throw; 36 37 } 38 39 public static void TryCast() 40 41 { 42 43 int i = 123; 44 45 string s = "Some string"; 46 47 object obj = s; 48 49 try 50 51 { 52 53 // Invalid conversion; obj contains a string, not a numeric type. 54 55 i = (int)obj; 56 57 // The following statement is not run. 58 59 Console.WriteLine("WriteLine at the end of the try block."); 60 61 } 62 63 finally 64 65 { 66 67 // Report that the finally block is run, and show that the value of 68 69 // i has not been changed. 70 71 Console.WriteLine("\nIn the finally block in TryCast, i = {0}.\n", i); 72 73 } 74 75 }