C# 异常之体系

C# 异常之体系

. 异常通常由应用程序(用户程序等)或运行库(公共语言运行库和应用程序运行库) 引发的异常. Exception 是所有异常类型的基类. 当发生错误时,系统或当前正在执行的应用程序通过引发包含关于该错误的信息的异常来报告错误. 异常发生后,将由该应用程序或默认异常处理程序进行处理. 若干异常类都直接从 Exception 类继承,其中包括两种主要类型的异常类:
1. ApplicationException 类,该作为用户定义的应用程序异常类型的基类. 2. SystemException 类,该类型是预定义的公共语言运行库异常类的基类.
这两个异常类构成了几乎所有的应用程序和运行库异常的基础.

. 当错误(这些错误是失败的运行库检查,如数组越界等错误导致的)发生时, 运行库就会引发 SystemException 或其派生类类型的异常.

. 相反 ApplicationException类型异常 是由用户程序引发,而不是由运行库引发.如果要创建自己的异常的,应从 ApplicationException 或 Exception 类派生这些异常. 不建议捕捉 SystemException , 在应用程序中引发 SystemException 也不是好的编程做法. 而通常,大多数直接从 Exception 派生的异常不需要为 Exception 类添加任何功能.

注意

通常我们所讲的异常一般都是指可与之交互的异常(也就是说我们可以对其进行一些处理,这些异常通常由应用程序引发),即非致命的异常.而象那些非常严重的异常,即那些由运行库引发或在不可恢复的情况中引发的异常,包括 ExecutionEngineException、StackOverflowException 和 OutOfMemoryException .

交互操作异常是从 SystemException 派生并由 ExternalException 进一步扩展的异常. 例如, COMException 是 COM Interop 操作过程中引发的异常,它从 ExternalException 派生. Win32Exception 和 SEHException 也从 ExternalException 派生.

C# 异常的发生

. 公共语言运行库支持基于 异常对象 和 受保护代码块概念 的异常处理模型. 即当运行库在异常发生时,运行库就会创建一个表示该异常的对象. 当然你也可以通过从适当的基异常派生类来创建自己的异常类.

. 而当发生非致命应用程序错误时,就会引发 ApplicationException 类及其派生类类型的异常.

. 我们可以通过使用 Throw 语句显式引发异常. 也可以使用 Throw 语句再次引发已经捕获的异常. 好的编码做法是向再次引发的异常添加信息以在调试时提供更多信息. 而异常的处理方法,在所有使用运行库的语言都以相似的方式处理异常. 即大多数语言都使用 try/catch/finally 形式的结构化异常处理.

C# 使用 try/catch 块捕捉异常

公共语言运行库 提供一种异常处理模型,该模型基于对象形式的异常表示形式, 即将程序代码和异常处理代码分到 try 块和 catch 块中.可以有一个或多个 catch 块,每个块都设计为处理一种特定类型的异常,或者将一个块设计为捕捉比其他块更具体的异常. 如果要处理在应用程序在执行期间某代码块发生的异常,则必须先该代码块放置在 try 块中. ( try 语句中的代码是 try 块), 并将处理由 try 块引发的异常的应用程序代码放在 catch 语句中,称为 catch 块. 零个或多个 catch 块与一个 try 块相关联,每个 catch 块包含一个确定该块能够处理的异常类型的类型筛选器.在 try 块中出现异常时,系统按所关联 catch 块在应用程序代码中出现的顺序搜索它们, 直到定位到处理该异常的 catch 块为止. 如果某 catch 块的类型筛选器指定了异常类型 T 或任何派生由异常类型 T 派生的异常类型,的则该 catch 块处理 T 类型及其派生类型的异常. 系统在找到第一个处理该异常的 catch 块后即停止搜索.因此,正如本节后面的示例所演示的那样,在应用程序代码中处理某类型异常的 catch 块必须在处理其基类型的 catch 块之前指定,所以通常处理 System.Exception 的 catch 块最后指定. 如果与 try 块相关联的所有 catch 块均不处理该异常,且当前 try 块嵌套在其他 try 块中, 则搜索与上一级 try 块相关联的 catch 块. 如果仍然没有找到用于该异常的 catch 块, 则将该异常沿调用堆栈向上传递,搜索上一个堆栈帧(即当前方法(或函数)的主调方法(或函数)) 来查找处理该异常的 catch 块,并一直查找,直到该异常得到处理或调用堆栈中没有更多的帧为止. 如果到达调用堆栈顶部却没有找到处理该异常的 catch 块,则由默认的异常处理程序处理该异常, 然后应用程序终止.

细节: 当发生异常时,该异常会沿堆栈向上传递,并查找合适 catch 块. 由前面看出 catch 语句的顺序很重要,应该将针对处理特定异常的 catch 块放在处理常规异常(一般指定某种异常的基类) catch 块的前面,否则编译器可能会发出错误. catch 块的查找方法是将异常的类型与 catch 块中指定的异常名称进行匹配. 如果没有找到特定的 catch 块,则由存在的常规 catch 块捕捉异常.如果也没有处理常规异常的 catch 块,公共语言运行库捕捉 catch 块没有捕捉的异常.根据运行库的配置,或者出现一个调试对话框, 或者程序停止执行并出现一个包含异常信息的对话框.

下面的代码示例使用 try/catch 块捕捉

InvalidCastException 该示例创建一个名为 Employee 的类,该类有单个属性——职员级别 (Emlevel) . PromoteEmployee 取得对象并增加职员级别. 将 DateTime 实例传递给 PromoteEmployee 方法时,发生 InvalidCastException .

using System;
public class Employee
{
   //Create employee level property.
   public int Emlevel
   {
      get
         {
         return(emlevel);
         }
      set
         {
         emlevel = value;
         }
   }
   int emlevel;
}

public class Ex13 
{
   public static void PromoteEmployee(Object emp)
   {
   //Cast object to Employee.
   Employee e = (Employee) emp;
   // Increment employee level.
   e.Emlevel = e.Emlevel + 1;
   }

   public static void Main()
   {
   try
      {
   Object o = new Employee();
   DateTime newyears = new DateTime(2001, 1, 1);
   //Promote the new employee.
   PromoteEmployee(o);
   //Promote DateTime; results in InvalidCastException as newyears is not an employee instance.
   PromoteEmployee(newyears);
      }
   catch (InvalidCastException e)
      {
      Console.WriteLine("Error passing data to PromoteEmployee method. " + e);
      }
   }
}
Published At
Categories with Web编程
Tagged with
comments powered by Disqus