异常处理

异常处理结构
  一、try-catch结构
  try
  {

   }

  catch(Exception exp)
  {
    Consle.WriteLine(“输入错误:"+exp.Message);

   }

  C#采用面向对象的方式来处理程序异常,每一个异常都是一个Exception对象,在catch语句中可以访问该对象。
  其中catch关键字后面括号中的Exception对象exp就表示所捕获的异常对象,其Message属性表示CLR给出的异常信息。Exception类型有一系列派生类,它们表示更为具体的异常类型,比如DivideByZeroException就表示除以0所引发的异常。如果在catch语句中指定了某个具体的异常类型,那么它只能捕捉这一类异常。
  catch(DivideByZeroException exp)
  {
   }
  如果catch代码段中没有使用到异常对象,那么在catch关键字后的括号里可以只写出异常的类型,而不必写出异常对象的名称;如果只写出catch关键字,那么默认捕获的异常类型是Exception。
  在try-catch异常处理结构中,一个try语句后面可以有多个并列的catch语句,每个catch语句用于捕捉和处理不同类型的异常。在发生了某个特定类型的异常后,程序就转入相应的catch代码,并在执行完后退出整个try-catch语句;如果列出的所有catch语句都不能处理异常,当前程序将非正常中止。

  二、try-catch-finally结构
  该结构对异常的捕获和处理方式与try-catch结构相同;但不论程序在执行过程中是否发生异常,finally代码段总是会被执行。
  下面的代码由用户依次输入一组数值,并输出这些数的总和及平均值:

 1 using System;
 2 
 3 public class Program
 4 {
 5     static viod Main()
 6     {
 7         int m = -1, n = 0;
 8         double sum = 0;
 9         Console.WriteLine("请依次输入一组数值,输入END结束:");
10         while (true)
11         {
12             try
13             {
14                 string s = Console.ReadLine();
15                 if (s.ToUpper() == "END")
16                     break;
17                 sum += double.Parse(s);
18                 n++;
19             }
20             catch (FormatException)
21             {
22                 Console.WriteLine("输入格式不正确,请重新输入:");
23             }
24             finally
25             {
26                 m++;
27             }
28         }
29         Console.WriteLine("您总共输入了{0}次,其中正确输入{1}次", m, n);
30         Console.WriteLine("数组之和为{0},平均值为{1}", sum, sum / n);
31     }
32 }

  当用户输入END时,程序将执行其中的break语句,但此时并不是立即跳出外围的while循环,而是执行完finally代码段后才跳出循环。如果不使用finally代码段,而是将语句m++直接放在catch代码段之后,用户输入END后就不会执行该语句,那么m的初始值就应当设为0。
 这说明finally语句具有强制执行的特性,即时是在前面的try代码段或catch代码段中遇到break、continue、goto等转移语句,finally代码段也不会被跳过。(PS:不管try中的代码有没有发生异常,finally都会被强制执行)
  C#的实数除法中除以0不会引发异常:0除以0得到的结果是非数字(NaN),而其他数除以0的结果是无穷大。
  C#还规定:在finally代码段中不允许使用return语句;如果在finally代码段中使用了break、continue或goto语句,那么该转移语句的目的地也必须在此代码段中。也就是说,finally代码段中的跳转语句不能跳出代码段之外。

  三、try-finally结构
  try-finally结构实际上只“捕获”而不“处理”异常,如果执行try代码段的过程中发生了错误,程序就会引发异常,但是finally代码段仍会被执行。

  四、异常的捕获和传播
    1.传播过程
    程序引发异常后,程序的控制权将在异常处理结构中转移,直至找到一个能够处理该异常的catch语句,否则程序终止运行,这个过程叫作异常传播,其步骤如下。
    (1)如果错误代码所在的异常处理结构中包含能够处理该异常的catch语句,那么程序控制权就转移给第一个这样的catch语句,异常传播结束。
    (2)如果没有找到能够处理该异常的catch语句,则程序通过当前的异常处理结构(如果存在finally代码带则执行它)。
    (3)如果程序到达更外层的一个异常处理结构,则转到第(1)步。
    (4)如果异常在当前方法中没有得到处理,则当前方法的执行被终止;若当前方法是程序主方法,那么整个程序结束运行。
    (5)否则,程序控制权转移给调用当前方法的代码,重复第(1)步。

 

 1 using System;
 2 
 3 public class Program
 4 {
 5     static viod Main()
 6     {
 7          try
 8          {
 9              int y = ReadRecip();
10              Console.WriteLine(100 / (10 = y));
11          }
12         catch (Exception exp)
13         {
14             Console.WriteLine("Main方法中发生异常:{0}",exp.GetType());
15         }
16     }
17     static int ReadRecip()
18     {
19         try
20         {
21             int x = ReadInt();
22             return 100 / x;
23         }
24         catch (DivideByZeroException exp)
25         {
26             Console.WriteLine("ReadRecip方法中发生异常:{0}", exp.GetType());
27             return 0;//方法中定义了返回值,如果在try中有方法的返回值,那么必须在catch中也必须指定相应类型的返回值;
//.并且还要记住finally虽然会被强制执行,但是它的代码段中不能有return,所以不能指望在finally中加上返回值而在catch中跳过不指定返回值
28 } 29 } 30 static int ReadInt() 31 { 32 Console.WriteLine("请输入一个整数:"); 33 return int.Parse(Console.ReadLine()); 34 } 35 }

 就如上面的ReadRecip方法中,方法中定义了返回值类型,如果在try中有方法的返回值,那么必须在catch中也必须指定相应类型的返回值;并且还要记住finally虽然会被强制执行,但是它的代码段中不能有return,所以不能指望在finally中加上返回值而在catch中跳过不指定返回值。

    2.Exception和异常信息
    Exception类是其他所有异常的基类,通过该类型的下列属性能够访问异常对象的基本信息。

  • Message:描述异常信息的字符串。
  • Source:引发异常的程序或对象的名称。
  • StackTrace:对异常传播的方法调用堆栈的描述。
  • TargetSite:引发异常的方法。
    3.异常层次结构
    Exception有两个常用的派生类:ApplicationException和SystemException,前者表示开发人员在程序中所引发的异常,后者表示系统所引发的系统异常。.NET类库中定义了SystemException的一系列派生类。
  • ArgumentException、FormatException:参数和格式异常;
  • ArithmeticE:与算术有关的异常,比如其派生类DivideByZeroException表示除以零所引发的异常;
  • InvalidOperationException:与对象操作有关的异常,比如其派生类ObjectDisposedE;
  • IOException:与文件操作有关的异常,其派生类DriveNotFoundException、DirectoryNotFoundException、FileNotFoundException和EndOfStreamException;
  • DataException:与数据访问有关的异常;
  • IndexOutOfRangeException:超出索引范围所引发的异常;
  • InvalidCastException:类型转换失败所引发的异常;
  • NullReferenceException:空对象引用所引发的异常;
  • NotSupportedException:调用的方法不受支持所引发的异常,比如对只读的文件流进行写入操作;
  • OutOfMemoryException:内存不足所引发的异常;
  • StackOverflowException:操作系统堆栈溢出所引发的异常。
    4.主动引发异常和自定义异常类型
      (1)try-catch和try-catch-finally这样的异常类型处理结构是为了避免在发生异常后程序终止。而在另一些情况下,程序代码需要主动引发异常,以便向用户报    告错误,或者阻止对象和方法的不合理使用。此时,异常代码的调用者就应当对异常进行捕获和处理。
    throw new ArgumentException();
    其中,throw语句用于引发一个异常,异常对象应跟在throw关键字之后。程序执行到throw语句就会引发异常并传播异常,之后的语句不再被执行;如果异常没有被捕获,整个程序就会终止。
    在创建Exception或其派生对象时,通常还可以在构造函数中指定专门的异常信息(即Exception的Message属性值),以便向类型或方法的使用者进行更详细的说明。
    throw new ArgumentException();
    throw new ArgumentException("姓名不能为空");
    throw new ArgumentOutOfRangeException("年纪必须在1~6之间");
      (2)自定义异常类型
      为了明确用途,自定义的异常类型通常应从Exception或ApplicationException类派生(除非是开发.NET Framework的扩展类库时才应考虑从SystemException类派生),并以“Exception”作为类名的结尾。
posted @ 2012-07-31 22:51  tc庄稼汉  阅读(614)  评论(0编辑  收藏  举报