# 异常处理 > 下面本小结重点讲异常处理语句 ## try-catch Try-catch 语句包含一个后接一个或多个 `catch` 子句的 `try` 块,这些子句指定不同异常的处理程序。 引发异常时,公共语言运行时 (CLR) 查找处理此异常的 `catch` 语句。 如果当前正在执行的方法不包含此类 `catch` 块,则 CLR 查看调用了当前方法的方法,并以此类推遍历调用堆栈。 如果未找到任何 `catch` 块,则 CLR 向用户显示一条未处理的异常消息,并停止执行程序。 `try` 块包含可能导致异常的受保护的代码。 将执行此块,直至引发异常或其成功完成。 例如,强制转换 `null` 对象的以下尝试会引发 [NullReferenceException](https://docs.microsoft.com/zh-cn/dotnet/api/system.nullreferenceexception) 异常: ```csharp object o2 = null; try { int i2 = (int)o2; // Error } ``` 尽管可以不带参数使用 `catch` 子句来捕获任何类型的异常,但不推荐这种用法。 一般情况下,只应捕获你知道如何从其恢复的异常。 因此,应始终指定派生自 [System.Exception](https://docs.microsoft.com/zh-cn/dotnet/api/system.exception) 的对象参数,例如: ```csharp catch (InvalidCastException e) { } ``` 可以使用同一 try-catch 语句中的多个特定 `catch` 子句。 在这种情况下,`catch` 子句的顺序很重要,因为 `catch` 子句是按顺序检查的。 在使用更笼统的子句之前获取特定性更强的异常。 如果捕获块的排序使得永不会达到之后的块,则编译器将产生错误。 ## throw 发出程序执行期间出现异常的信号。 语法为:`throw [e]` `e` 是一个派生自 [System.Exception](https://docs.microsoft.com/zh-cn/dotnet/api/system.exception) 的类的实例。 下例使用 `throw` 语句在传递给名为 `GetNumber` 的方法的参数与内部数组的有效索引不对应时引发 [IndexOutOfRangeException](https://docs.microsoft.com/zh-cn/dotnet/api/system.indexoutofrangeexception) 。 ```csharp using System; namespace Throw2 { public class NumberGenerator { int[] numbers = { 2, 4, 6, 8, 10, 12, 14, 16, 18, 20 }; public int GetNumber(int index) { if (index < 0 || index >= numbers.Length) { throw new IndexOutOfRangeException(); } return numbers[index]; } } ``` 然后方法调用方使用 `try-catch` 或 `try-catch-finally` 块来处理引发的异常。 下例处理由 `GetNumber` 方法引发的异常。 ```csharp using System; public class Example { public static void Main() { var gen = new NumberGenerator(); int index = 10; try { int value = gen.GetNumber(index); Console.WriteLine($"Retrieved {value}"); } catch (IndexOutOfRangeException e) { Console.WriteLine($"{e.GetType().Name}: {index} is outside the bounds of the array"); } } } // The example displays the following output: // IndexOutOfRangeException: 10 is outside the bounds of the array ``` ### 重新引发异常 `throw` 也可以用于 `catch` 块,以重新引发在 `catch` 块中处理的异常。 ### throw 表达式 从 C# 7.0 开始,`throw` 可以用作表达式和语句。 这允许在以前不支持的上下文中引发异常。 这些方法包括: - 条件运算符。 ```csharp private static void DisplayFirstNumber(string[] args) { string arg = args.Length >= 1 ? args[0] : throw new ArgumentException("You must supply an argument"); if (Int64.TryParse(arg, out var number)) Console.WriteLine($"You entered {number:F0}"); else Console.WriteLine($"{arg} is not a number."); } ``` - null合并运算符 ```csharp public string Name { get => name; set => name = value ?? throw new ArgumentNullException(paramName: nameof(value), message: "Name cannot be null"); } ``` - lambda表达式或方法 ```csharp DateTime ToDateTime(IFormatProvider provider) => throw new InvalidCastException("Conversion to a DateTime is not supported."); ```