本章旨在教会你:
● 使用try,catch和finally语句处理异常
● 使用checked和unchecked关键字控制整数溢出
● 使用throw关键字从自己写的方法中抛出异常
● 使用一个finally块,确保即使在发生异常之后,代码也总是在运行
到目前为止,你已经经学会了阅读和自己写方法所需的核心Microsoft Visual C#语句,知道了如何用操作符来创建值,如何用if和switch语句来选择性地运行代码,如何使用while,for和do语句来重复地运行代码。然而,前几章一直没有提到程序可能出错的问题。事实上,很难保证一段代码总是像希望的那样工作。有可能因为大量原因而发生问题,其中许多原因不是程序员能够控制的。任何应用程序部必须能够检测错误,并采取优美的方式来处理它们。作为第1部分的最后一章,本章将讲述c#语言如何通过抛出异常来通知已经发生了一个错误,如何使用try,catch和finally语句来捕捉和处理这些异常所代表的错误。通过本章的学习, 读者将进一步掌握c#语言,为顺利学习第2部分的内容打下坚实的基础。
6.1处理错误生活并非总是一帆风顺。轮胎可能被扎破,电池可能用完,螺丝起子并非总在老地方,应用程序的用户可能采取我们意想不到的方式行动。错误可能在程序运行的任何何阶段发生。那么,应该怎样检测和恢复它们呢?多年来,人们为此开发了大量机制。早期系统(如Unix)采用的典型方案要求在每次一个方法出错的时候,都由操作系统设置一个特殊的全局变量。每次调用方法之后,都检查全局变景,判断方法是否成功。和现代的其他大多数面向对象编程语言一样.C#没有使用这种痛苦的、折磨人的方式来处理错误。相反,它们使用的是异常(exception)。为了写一个可靠的c#应用程序,必须多多了解异常。
6.2尝试代码和捕捉异常在C#中,利用异常和异常处理程序,可以很容易地将用于实现程序中逻辑的代码与错误处理代码区分开。为了写一个能处理异常的程序,需要做下面两件事情。
1,代码要放到一个try块中(try是c#关键字)。代码运行时,它会尝试执行try块内的所有语句。如果没有任何语句产生一个异常,这些语句将一个接一个运行,直到全部完成。然而,一旦出现异常,就会跳出try块,并进入一个catch处理程序中执行。
2.在try块后而紧接着写一个或多个catch处理程序(catch也是C#关键字),用它们处理任何发生的错误。每个catch处理程序都负责捕捉并处理一种特定类型的异常,你可以在一个try块后面写多个catch处理程序。try块中的任何一个语句造成错误,“运行时”(runtime)都会生成并抛出一个异常。然后,“运行时”将检查try块之后的catch处理程序,将控制权直接移交给一个匹配的处理程序。
在下面的例子中,我们将在一个try块内尝试将用户在文本框中输入的内容转换成整数值,调用一个方法来计算一个值,并将结果写入一个文本框。为了将字符串转换成整数.要求字符串中包含的是有效的字符,而不能是一个随意的字符序列。如果字符串中包含无效的字符.int.Parse方法会抛出一个FormatException异常,并将控制权移交给对应的catch处理程序。catch处理程序结束之后,程序将从处理程序之后的第一个语句继续执行。
try
{
int leftHandSide=int.Parse(lhsOperand.Text);
int rightHandSide=int.Parse(rhsOperand.Text);
int answer=doCalculation(leftHandSide,rightHandSide);
result.Text=answer.ToString();
}
catch(FormatException fEx)
{
//在此处理异常
……
}
6.2.1处理异常catch处理程序采用与方法参数相似的语法来指定要捕捉的异常。在前例中,一旦抛出一个FormatException异常,fEx变量就会被填充一个对象,对象中包含了异常的细节。FormatException类型提供了大量属性用于检查造成异常的确切原因。其中不少属性是所有异常都有的。例如,Message属性包含了对错误的一段文本描述。处理异常时,你可以自由利用这个属性的内容。例如,可以把它记录到一个日志文件中,或者向用户显示一条有意义的消息,并要求他们重试一遍。
6.2.2未处理的异常如果一个try块抛出一个异常,但没有对应的catch处理程序,会发生什么情况呢?在前例中,lhsOperand字段可能包含一个有效整数的字符串形式,但它代表的整数超出了c#允许的整数范围(例如”2147483648”)。在这种情况下,int.Parse语句将抛山一个OverflowException异常,而我们写的那个catch处理程序只能捕捉FormatException异常。在这种情况下,如果try块是某个方法的一部分,那个方法将立即退出,并返回它的调用方法。如果它的调用方法使用了一个try块,运行时(runtime)会尝试定位try块之后的一个相匹配的catch处理程序,并执行它。如果调用方法没有使用try块,或者没有找到匹配的catch处理程序,那个调用方法也将退出,并返回它的更上一级的调用方法……以此类推。如果最终找到一个匹配的catch处理程序,就会运行它,然后从捕捉(到异常的)方法的catch处理程序之后的第一个语句继续执行。
重要提示:捕捉了一个异常之后,将从“捕捉方法”中的catch处理程序之后的第一个语句继续,这个catch处理程序是实际捕捉到异常的catch块。程序控制不会返回当初造成异常的方法。
由内向外遍历了所有调用方法之后,假如“运行时”(runtime)找不到一个相匹配的catch处理程序,整个程序就会终止,并报告一个未处理的异常。在Visual Studi0 2008“调试”模式中运行应用程序(选择“调试”“启动调试”)就会出现下图所示的对话框,调试器将接管应用程序,便于判断造成异常的原因。
l