我们开发了函数,当函数的调用者在使用函数的时候,我们希望函数的调用者可以正确的使用函数,比如给予函数正确的参数值。但在实际的过程中,函数的调用者可能由于各种原因给予了错误的值。在这种情况下,我们需要向调用者抛出错误信息,并中断程序的执行,这个过程我们称为异常。
程序必须能够统一处理在执行期间发生的错误。公共语言运行库提供了一个模型,以统一的方式通知程序发生的错误,从而为设计容错软件提供了极大的帮助。所有的 .NET Framework 操作都通过引发异常来指示出现错误。
传统上,语言的错误处理模型依赖于语言检测错误和查找错误处理程序的独特方式,或者依赖于操作系统提供的错误处理机制。运行库实现的异常处理具有以下特点:
q 处理异常时不用考虑生成异常的语言或处理异常的语言。
q 异常处理时不要求任何特定的语言语法,而是允许每种语言定义自己的语法。
q 允许跨进程甚至跨计算机边界引发异常。
与其他错误通知方法(如返回代码)相比,异常具有若干优点。不再有出现错误而不被人注意的情况。无效值不会继续在系统中传播。不必检查返回代码。可以轻松添加异常处理代码,以增加程序的可靠性。最后,运行库的异常处理比基于 Windows 的 C++ 错误处理更快。
抛出的异常有三种对象:
q System.Exception是最简单的异常对象
q 抛出系统定义的最适合的异常对象
q 自定义的异常对象
以下的代码是抛出System.Exception异常
以下的代码是抛出.NET Framework定义中最适合的异常
在RectangleArea函数中抛出的异常是最基本的异常。在SquareArea函数中抛出的是.NET Framework定义的ArgumentOutOfRangeException异常,该异常的含义是“当参数值超出调用的方法所定义的允许取值范围时引发的异常”。
当我们给予错误的参数时
System.Console.WriteLine("该正方形的面积为{0}", SquareArea(-2));
将出现异常
以下是常用的异常,在决定抛出异常的时候,请先查看.Net是否提供了合适的异常
异常类 |
用途说明 |
System.TimeoutException |
超时 |
System.TimeZoneNotFoundException |
时区不正确 |
System.TypeLoadException |
类型初始化不正确 |
System.UnauthorizedAccessException |
IO错误 |
System.UriFormatException |
Uri格式不正确 |
System.Threading.LockRecursionException |
资源被锁 |
System.OutOfMemoryException |
内存不够 |
System.StackOverflowException |
嵌套死循环引起栈溢出 |
System.FormatException |
提供的数据格式不正确 |
System.IndexOutOfRangeException |
索引超出 |
System.RankException |
数组纬度错误 |
当系统预定义的异常无法满足我们的要求,我们可以创建自己的异常。比如我们编写一个函数,该函数接受用户的给予一个标识,方法通过该标识在数据库中寻找相应的人员信息,如果没有找到则抛出一个异常。我们可以自己编写一个异常。自定义异常需要了解.Net的异常层次结构:
有两种类型的异常:由执行程序生成的异常和由公共语言运行库生成的异常。另外,还有由应用程序或运行库引发的异常的层次结构。
Exception 是异常的基类。若干个异常类直接从 Exception 继承,其中包括 ApplicationException 和 SystemException。这两个类构成几乎所有运行库异常的基础。大多数直接从 Exception 派生的异常不为 Exception 类添加任何功能。错误发生时,运行库引发 SystemException 的适当派生类。这些错误是失败的运行库检查导致的,它们可在任何方法的执行过程中发生。如果设计创建新异常的应用程序,应从 Exception 类派生那些异常。不建议捕捉 SystemException,在应用程序中引发 SystemException 也不是好的编程做法。
我们定义自己的异常从SystemException类继承
一般异常的命名规则是以Exception为后缀。
在最后我们需要了解异常的处理一些内部概念。当异常发生的时候,.Net做了些什么呢?异常发生时,运行库开始执行由下列两步组成的过程:
q 运行库在数组中搜索满足下列条件的第一个受保护块: 保护包含当前执行的指令的区域,而且包含异常处理程序或包含处理异常的筛选器。
q 如果出现匹配项,运行库创建一个 Exception 对象来描述该异常。然后运行库执行位于发生异常的语句与处理该异常的语句之间的所有 Finally 语句或错误处理语句。请注意,异常处理程序的顺序很重要:最里面的异常处理程序最先计算。还请注意,异常处理程序可以访问捕捉异常的例程的局部变量和本地内存,但引发异常时的任何中间值都会丢失。
如果当前方法中没有出现匹配项,则运行库搜索当前方法的每一个调用方,并沿着堆栈一直向上查找。如果任何调用方都没有匹配项,则运行库允许调试器访问该异常。如果调试器不能附加到该异常,则运行库引发 UnhandledException 事件。如果没有 UnhandledException 事件的侦听器,则运行库转储堆栈跟踪并结束程序。换句话说就是:应用程序崩溃。