13.exception.md 4.1 KB

异常处理

下面本小结重点讲异常处理语句

try-catch

Try-catch 语句包含一个后接一个或多个 catch 子句的 try 块,这些子句指定不同异常的处理程序。

引发异常时,公共语言运行时 (CLR) 查找处理此异常的 catch 语句。 如果当前正在执行的方法不包含此类 catch 块,则 CLR 查看调用了当前方法的方法,并以此类推遍历调用堆栈。 如果未找到任何 catch 块,则 CLR 向用户显示一条未处理的异常消息,并停止执行程序。

try 块包含可能导致异常的受保护的代码。 将执行此块,直至引发异常或其成功完成。 例如,强制转换 null 对象的以下尝试会引发 NullReferenceException 异常:

object o2 = null;
try
{
    int i2 = (int)o2;   // Error
}

尽管可以不带参数使用 catch 子句来捕获任何类型的异常,但不推荐这种用法。 一般情况下,只应捕获你知道如何从其恢复的异常。 因此,应始终指定派生自 System.Exception 的对象参数,例如:

catch (InvalidCastException e)
{
}

可以使用同一 try-catch 语句中的多个特定 catch 子句。 在这种情况下,catch 子句的顺序很重要,因为 catch 子句是按顺序检查的。 在使用更笼统的子句之前获取特定性更强的异常。 如果捕获块的排序使得永不会达到之后的块,则编译器将产生错误。

throw

发出程序执行期间出现异常的信号。

语法为:throw [e]

e 是一个派生自 System.Exception 的类的实例。 下例使用 throw 语句在传递给名为 GetNumber 的方法的参数与内部数组的有效索引不对应时引发 IndexOutOfRangeException

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-catchtry-catch-finally 块来处理引发的异常。 下例处理由 GetNumber 方法引发的异常。

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 可以用作表达式和语句。 这允许在以前不支持的上下文中引发异常。 这些方法包括:

  • 条件运算符。
  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合并运算符
  public string Name
  {
      get => name;
      set => name = value ??
          throw new ArgumentNullException(paramName: nameof(value), message: "Name cannot be null");
  }
  • lambda表达式或方法
  DateTime ToDateTime(IFormatProvider provider) =>
           throw new InvalidCastException("Conversion to a DateTime is not supported.");