c#中的捕获派生类异常

在尝试捕获涉及基类和派生类的异常类型时要注意catch子句的排序方式,因为基类的catch子句也会匹配它的任何派生类。例如,由于所有异常的基类都是Exception,因此带有catch的Exception会捕获所有可能的异常。当然,根据前面的描述,使用不带异常类型的catch提供了一种捕获所有异常的清晰方式。然而在其他背景下,捕获派生类异常的问题非常重要,尤其是在创建自己的异常时。

如果要捕获基类类型的异常和派生类类型的异常,那么将派生类先放在catch序列中。之所以有必要这样做,是因为基类catch也会捕获所有派生类。幸运的是,这个规则是自实施的,因为先放置基类会导致编译时错误。

下面的程序创建了分别名为ExceptA和ExceptB的两个异常类。ExceptA派生自Exception,ExceptB派生自ExceptA。然后程序抛出各个类型的异常。为了简单起见,仅提供了一个构造函数(接受一个描述异常的字符串作为实参)。但是要记住,在商业代码中,自定义的异常类一般会提供Exception定义的所有4个构造函数。

 
 
  1. // Derived exceptions must appear before base class exceptions.  
  2. using System;  
  3.  
  4. // Create an exception.  
  5. class ExceptA : Exception {  
  6.   public ExceptA(string str) : base(str) { }  
  7.  
  8.   public override string ToString() {  
  9.     return Message;  
  10.   }  
  11. }  
  12.  
  13. // Create an exception derived from ExceptA  
  14. class ExceptB : ExceptA {  
  15.   public ExceptB(string str) : base(str) { }  
  16.  
  17.   public override string ToString() {  
  18.     return Message;   
  19.   }  
  20. }  
  21.  
  22. class OrderMatters {  
  23.   static void Main() {  
  24.     for(int x = 0; x < 3; x++) {  
  25.       try {  
  26.         if(x==0) throw new ExceptA("Caught an ExceptA exception");  
  27.         else if(x==1) throw new ExceptB("Caught an ExceptB exception");  
  28.         else throw new Exception();  
  29.       }  
  30.       catch (ExceptB exc) {  
  31.         Console.WriteLine(exc);  
  32.       }  
  33.       catch (ExceptA exc) {  
  34.         Console.WriteLine(exc);  
  35.       }  
  36.       catch (Exception exc) {  
  37.         Console.WriteLine(exc);  
  38.       }  
  39.     }  
  40.   }  

该程序的输出如下所示:

 
 
  1. Caught an ExceptA exception  
  2. Caught an ExceptB exception  
  3. System.Exception: Exception of type 'System.Exception' was thrown.  
  4.    at OrderMatters.Main() 

注意catch子句的顺序,这是这些子句能够运行的唯一顺序。由于ExceptB是从ExceptA派生的,因此ExceptB的catch必须在ExceptA的catch之前。类似地,Exception(它是所有异常的基类)的catch必须最后出现。要亲自证实这一点,可以重新排列catch子句。这样做会导致编译时错误。

问:既然异常通常表示特定的错误,那么为什么要捕获基类异常呢?

答:捕获基类异常的catch子句可以捕获整个类别的所有异常,可以使用一个catch处理它们,从而可以避免重复的代码。例如,可以创建一组描述某种设备错误的异常。如果异常处理程序只是告诉用户发生了一种设备错误,那么可以对这种类型的所有异常使用一个共同的catch。处理程序可以简单地显示Message字符串。由于完成该操作的代码对于所有异常都是相同的,因此只使用一个catch就可以响应所有设备异常。

在本项目中,将创建可以由第9章的"试一试"一节中开发的队列类使用的两个异常类。这两个异常类将指出队列满与队列空时错误发生的条件。当发生错误时,分别由Put()和Get()方法抛出异常。为了简洁起见,本示例仅向SimpleQueue类中添加这些异常,但是可以方便地将它们合并到其他队列类中。为了简短起见,异常类仅实现程序中实际使用的构造函数(它是接受一个描述异常的实参的构造函数)。您可以尝试亲自添加其他构造函数。

操作步骤

(1) 创建名为QExcDemo.cs的文件。

(2) 在QExcDemo.cs中,定义如下异常:

 
 
  1. // Add exception handling to the queue classes.  
  2.  
  3. using System;  
  4.  
  5. // An exception for queue-full errors.  
  6. class QueueFullException : Exception {  
  7.   public QueueFullException(string str) : base(str) { }  
  8.   // Add other QueueFullException constructors here, if desired.  
  9.  
  10.   public override string ToString() {  
  11.     return "\n" + Message;  
  12.   }  
  13. }  
  14.  
  15. // An exception for queue-empty errors.  
  16. class QueueEmptyException : Exception {  
  17.   public QueueEmptyException(string str) : base(str) { }  
  18.   // Add other QueueEmptyException constructors here, if desired.  
  19.  
  20.   public override string ToString() {  
  21.     return "\n" + Message;  
  22.   }  
  23. 当试图将元素存储到已满的队列中时,生成QueueFullException异常。当试图从空队列中删除元素时,生成QueueEmptyException异常。

    (3) 按如下代码所示修改SimpleQueue类,使它在发生错误时抛出异常。将修改后的类添加到QExcDemo.cs中。

        
        
    1. // A simple, fixed-size queue class for 
      characters that uses exceptions.
       
    2. class SimpleQueue : ICharQ {      
    3.   char[] q; // this array holds the queue      
    4.   int putloc, getloc; // the put and get indices      
    5.       
    6.   // Construct an empty queue given its size.     
    7.   public SimpleQueue(int size) {   
    8.     q = new char[size+1]; // allocate memory for queue      
    9.     putloc = getloc = 0;      
    10.   }      
    11.      
    12.   // Put a character into the queue.      
    13.   public void Put(char ch) {  
    14.     if(putloc==q.Length-1)   
    15.       throw new QueueFullException("Queue Full! Max length is " +  
    16.                                     (q.Length-1) + ".");  
    17.           
    18.     putloc++;      
    19.     q[putloc] = ch;      
    20.   }      
    21.       
    22.   // Get a character from the queue.     
    23.   public char Get() {  
    24.     if(getloc == putloc)   
    25.       throw new QueueEmptyException("Queue is empty.");  
    26.         
    27.     getloc++;      
    28.     return q[getloc];      
    29.   }      

    向SimpleQueue类中添加异常可以以合理的方式处理队列错误。SimpleQueue类以前的版本只是简单地报告错误。抛出异常的方式要好很多,因为它允许使用SimpleQueue类的代码以适当的方式处理错误。

    (4) 为了尝试使用更新后的SimpleQueue类,将如下所示的QExcDemo类添加到QExcDemo.cs中。

        
        
    1. // Demonstrate the queue exceptions.  
    2.  
    3. class QExcDemo {      
    4.   static void Main() {      
    5.     SimpleQueue q = new SimpleQueue(10);      
    6.     char ch;      
    7.     int i;      
    8.       
    9.     try {   
    10.       // Overrun the queue.  
    11.       for(i=0; i < 11; i++) {  
    12.         Console.Write("Attempting to store : " +  
    13.                          (char) ('A' + i));  
    14.         q.Put((char) ('A' + i));      
    15.         Console.WriteLine(" -- OK");  
    16.       }  
    17.       Console.WriteLine();  
    18.     }  
    19.     catch (QueueFullException exc) {  
    20.       Console.WriteLine(exc);  
    21.     }  
    22.     Console.WriteLine();  
    23.      
    24.     try {  
    25.       // Over-empty the queue.  
    26.       for(i=0; i < 11; i++) {       
    27.         Console.Write("Getting next char: ");  
    28.         ch = q.Get();      
    29.         Console.WriteLine(ch);      
    30.       }  
    31.     }  
    32.     catch (QueueEmptyException exc) {  
    33.       Console.WriteLine(exc);  
    34.     }   
    35.   }      

    (5) 为了创建程序,必须使用IQCar.cs文件编译QExcDemo.cs。IQChar.cs中包含了队列接口。当运行QExcDemo时,将看到如下输出:

        
        
    1. Attempting to store : A -- OK  
    2. Attempting to store : B -- OK  
    3. Attempting to store : C -- OK  
    4. Attempting to store : D -- OK  
    5. Attempting to store : E -- OK  
    6. Attempting to store : F -- OK  
    7. Attempting to store : G -- OK  
    8. Attempting to store : H -- OK  
    9. Attempting to store : I -- OK  
    10. Attempting to store : J -- OK  
    11. Attempting to store : K  
    12. Queue Full! Max length is 10.  
    13.  
    14. Getting next char: A  
    15. Getting next char: B  
    16. Getting next char: C  
    17. Getting next char: D  
    18. Getting next char: E  
    19. Getting next char: F  
    20. Getting next char: G  
    21. Getting next char: H  
    22. Getting next char: I  
    23. Getting next char: J  
    24. Getting next char:   
    25. Queue is empty. 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值