标签:
转载:http://www.cnblogs.com/doit8791/archive/2012/05/08/2489471.html
以前写Delphi程序一直不注意异常处理,对其异常处理的机制总是一知半解,昨天程序中的一个bug ,让我对异常有了更深入的认识,必须要对可能产生异常的地方进行异常处理,否则可能给程序造成灾难。
就像昨天,因为写的 filecopy 函数没有做异常捕获处理,导致复制文件出错时整个程序崩溃,用户只能通过杀进程的方式重启程序再进行其他操作。后来对程序进行了异常处理,遇到意外时只是提示一下用户,然后可以继续运行下去,表现的很完美,才意识到异常处理的重要性,故要总结下Delphi 异常处理相关的知识
Delphi的异常处理的机制介绍
Delphi异常处理机制建立在保护块(protected blocks)的概念上。所谓保护块是用保留字try 和 end 封装的一段代码。保护块的作用是当应用程序发生错误的时候自动创建一个相应的异常类(Exception)。程序可以捕获并处理这个异常类,以确保程序的正常结束以及资源的释放和数据不受破坏。如果程序不进行处理,则系统会自动提供一个消息框。每一段程序都有可能产生错误!这是软件业的一个不容置疑的现象和规律。
传统的处理错误的方式和异常处理的联系和区别
事实上,传统的 if...else...结构完全可以解决所有的错误,使用Exception 机制也没能够回避在最原始的层次,通过遍历可能的情况来产生异常的做法,但是异常提供了一种更加灵活和开放的方式,使得后来的编程者可以来根据实际的情况处理这种错误,而不是使用预先设定好的处理结果
一、异常的来源
在Delphi的应用程序中,下列的情况比较有可能产生异常
1) 文件处理
2) 内存分配
3) Windows资源
4) 运行时创建对象和窗体
5) 硬件和操作系统冲突
二、异常处理
1. try... except... end;
在 try体内的代码发生异常时,系统将转向 except部分进行异常的处理。这是Delphi 处理异常的最基本的方式之一。try语句块指出来需要进行异常保护的代码。如果在这部分有不正常的事情发生,则引发一个异常对象。 except 是异常处理部分,被保护部分引发的异常对象将执行 <异常处理语句> 或由这部分代码捕获并进行处理
try ..except ..end 语句的一般格式如下
try //try保护代码块 被保护语句块 except //异常处理块 异常处理语句(如果异常不发生,就不执行) end;
或者
try //try保护代码块 被保护语句 except //异常处理块 on <异常处理对象类型1> do <语句1> //捕获指定类型的异常对象,进行处理 on <异常处理对象类型2> do <语句2> //捕获指定类型的异常对象,进行处理 else <语句 n+1> //缺省的异常处理代码 end;
2. try... finally... end;
这种异常处理结构一般用于保护 Windows的资源分配等方面,它确保了无论 try 体内的代码是否发生异常,都需要由系统进行最后的统一处理的一些 Windows对象的正确处理
和 try... except... end不同,该结构的finally部分总被执行。在 try-finally语句中,当 try部分产生异常后,应用程序直接执行 finally部分的资源释放语句
try finally语句的一般格式如下
try //try保护代码块 被保护语句 finally //异常处理块 异常处理语句 //无论异常是否发生,都必须处理 end;
若用作创建一个资源保护块时,它的格式可以写成:
(分配系统资源) try (使用系统资源的语句) finally (释放系统资源) end;
3. 不存在 try... except ... finally... end 结构来既处理异常,又保护资源分配的结构
但是,try... except... end 结构允许嵌套到 try... finally... end结构中,从而实现既处理异常,又保护资源的分配
4. raise:知道一些情况不合理,直接手工弹异常对话框。
比如
raise 异常类.Create(‘异常的缺省说明‘);
5. try... finally结构和 try... except 结构在用法上主要有以下区别
1) 对于try...finally结构来说,不管try部分的代码是否触发异常,finally部分总是执行的。如果发生异常,就提前跳到finally部分。而对于try...except结构来说,只有当触发了异常后,才会执行except部分的代码。
2) 在 try... except 结构中,当异常被处理后异常对象就被释放,除非重新触发异常。而在 try... finally 结构中,及时 finally部分对异常做了处理,异常对象依然存在
3) finally 部分不能处理特定的异常,因为它没有 try... except 结构中的异常句柄,无法知道确切的异常类型。因此,在 finally 部分只能对异常作笼统的处理
4) 在 try... finally 结构中,如果在 try 部分调用标准命令 exit、break或 continue,将导致程序的执行提前跳到 finally部分。finally部分不允许调用上述三个命令
三、Delphi中的异常类结构
Delphi 提供的所有异常类都是 Exception的子类。用户也可以从 Exception派生一个自定义的异常类。即 Exception是所有异常类的基类,它并不是以 ‘T‘ 开头的,而是以 ‘E‘ 开头,它的派生类也是以 ‘E‘ 开头的。
Delphi提供了一个很庞大的异常类体系,从大的方面可以把异常类分为运行库异常、对象异常、组件异常三类
1.运行库异常类(RTL Exception)
运行库异常类可以分为七类,它们都定义在SysUtils 库单元中
1.1. I/O异常
I/O异常类 EIOOutError 是在程序运行中试图对文件或外设进行操作失败之后产生的,它从 Exception 派生后增加了一个公有数据成员 ErrorCode,用于保存所发生错误的代码。这一成员可用于在发生 I/O 异常后针对不同的情况采取不同的策略
当设置编译指令 {$I-} 时,不产生 I/O异常类而是把错误代码返回到预定义变量 IOResult中
1.2堆异常
堆异常是在动态内存分配中产生的,包括两个雷 EOutOfMemory 和EInvalidPointer,如下表所示
堆异常类 | 引发条件、产生原因 |
EOutOfMemory | 没有足够的控件用于满足所要求的内存分配 |
EInvalidPointer | 非法指针。一般是由于程序试图去释放一个已经释放的指针而引起的 |
1.3整数异常
整数异常都是从一个 EIntError 类派生的,但是程序运行中引发的总是它的子类:EFivByZero,ERangeError,EIntOverFlow,如下表
异常类 | 引发条件 |
EDivByZero | 试图被零除 |
ERangeError | 整数表达式越界 |
EIntOverFlow | 整数操作溢出 |
ERangeError 当一个整数表达式的值超过一个特定整数类型分配的范围时引发。比如下面一段代码将引发一个ERangeError异常
标签:
原文地址:http://www.cnblogs.com/xumenger/p/4460788.html