3.9 异常处理
异常是指程序在运行时产生的错误,借助C#的异常处理系统,能够以结构化的、可控制的方式来处理运行时错误。
异常处理的主要优点是,它可以自动加载许多错误处理代码,而在以前,开发人员必须手动把它们输入到任何大型程序中。
3.9.1 SystemException类
在C#中,使用类表示异常。
所有的异常类都由内置的异常类Exception派生而来,该类是System名称空间的一部分。
所有的异常类都是Exception类的子类。
SystemException类是Exception类的一个重要子类。CLR产生的所有异常都来自于该异常类。
System中的常用标准异常如下。
1)ArrayTypeMismatchException:所有存储的值类型与数组类型不兼容。
2)DivideByZeroException:被零除。
3)IndexOutOfRangeException:数组索引超出边界。
4)InvalidCastException:运行时强制转换无效。
5)OutOfMemoryException:没有足够的空闲内存支持程序继续执行。
6)OverflowException:运算溢出。
7)NullReferenceException:试图对空引用进行操作。
3.9.2 使用try和catch关键字
使用try和catch关键字配合来组织易错程序代码,是C#中典型的异常处理方式。以下是try-catch代码组织方式的结构。
查看下列代码。
上述代码运行之后,因为循环体中i的大小会超过数组元素的上界,会引发“数组索引超出边界”的异常,则代码会马上跳转到catch后的代码段,运行其中的代码。
3.9.3 使用异常处理的优点
异常处理的最大优点之一是,它允许程序对错误做出响应并继续执行。编写下列代码并运行。
成功运行上述代码之后,读者会发现,程序在运行到i等于1和i等于4时都会抛出“DivideByZeroException”即“被零除”的错误。在显示“不能被零除!”的错误信息之后,程序会继续运行。
3.9.4 使用多条catch子句
也可以使用多条catch子句接收异常,在发生不同异常的时候,由不同catch子句接收相应的异常。观察下列代码。
运行上述代码,会发现运行结果中出现两次“不能被零除!”的提示,最后出现“超出数组范围了!”的提示,即为使用多条catch子句接收异常的运行效果。
3.9.5 捕获所有异常
如果无法确定会出现哪种异常,仍然想使用异常处理的try-catch子句。则可以在catch后面不列出异常名称,而直接给出响应代码。观察下列程序。
注意:大多数情况下,不应该使用“捕获所有异常”的处理程序作为异常处理的方式。通常最好是分别处理代码产生的每个异常。不适当地使用“捕获所有异常”的处理程序会导致掩盖原本在测试期间可以捕获的错误。
3.9.6 手动抛出异常(throw)
在某些情况下,需要程序“制造”异常,即在上述异常都没有发生的情况下,手动抛出异常。这就需要使用“throw”关键字。抛出的异常必须使用new关键字,后跟一个具体的异常名称。如throw new DivideByZeroException()。观察下列代码。
3.9.7 finally语句
有时必须为程序离开try/catch块执行的操作编写一段代码。可以添加在try/catch结构后面的finally块中。
注意:无论try/catch块在什么时候因为什么条件结束,finally块只要存在都将必然执行。也就是说,不论try块是正常结束还是异常结束,最终都会执行finally块中的代码。即使try块中的代码或catch语句中的代码使得该方法返回,finally块也将执行。