当前位置:编程学习 > Delphi >>

Delphi异常处理总结

Delphi异常处理总结
           以前写delphi程序一直不注意异常处理,对其异常处理机制总是一知半解,昨天程 序中的一个bug,让我对异常有了更深入的认识,必须要对可能产生异常的地方进行异常处理,否则可能给程序造成灾难,就像昨天,因为写的filecopy 函数没有做异常捕获处理,导致复制文件出错时整个程序崩溃,用户只能通过杀进程的方式重启程序再进行其它操作(汗~)。后来对程序进行异常处理,遇到意外 只是提示下用户,然后可以继续运行下去,表现很完美,才意识到异常处理的重要性,故要总结下Delphi异常处理相关的知识。

            Delphi异常处理机制建立在保护块(ProtectedBlocks)的概念上。所谓保护块是用保留字try和end封装的一段代码。保护块的作用是当应用程序发生错误时自动创建一个相应的异常类 (Exception)。程序可以捕获并处理这个异常类,以确保程序的正常结束以及资源的释放和数据不受破坏。如果程序不进行处理,则系统会自动提供一个消息框。每一段程序都有可能产生错误!这是软件业的一个不容置疑的现象和规律。事实上,传统的if…else…结构完全可以解决所有的错误,使用 Exception机制也没能够回避在最原始的层次,通过遍历可能的情况来产生异常的做法,但异常提供了一种更加灵活和开放的方式,使得后来的编程者可以来根据实际的情况处理这种错误,而不是使用预先设定好的处理结果。

常的来源
  在Delphi的应用程序中,下列的情况都比较有可能产生异常。  
  (1)文件处理  
  (2)内存分配  
  (3)Windows资源 
  (4)运行时创建对象和窗体  
  (5)硬件和操作系统冲突


一、异常的来源
  在Delphi的应用程序中,下列的情况都比较有可能产生异常。  
  (1)文件处理  
  (2)内存分配  
  (3)Windows资源 
  (4)运行时创建对象和窗体  
  (5)硬件和操作系统冲突


二、异常处理

(1)try…except…end;  

在try体内的代码发生异常时,系统将转向except部分进行异常的处理。这是 Delphi处理异常的最基本的方式之一。try语句块指出了需要进行异常保护的代码。如果在这部分有不正常的事件发生,则引发一个异常对象。 except是异常处理部分,被保护部分引发的异常对象将执行<异常处理语句>或由这部分代码捕获并进行处理。

try except语句的一般格式如下:

try //try保护代码块

被保护语句

except //异常处理块

异常处理语句 //异常不发生,不处理

end;

try //try保护代码块

被保护语句

except //异常处理块

on <异常对象类型1> do <语句1> //捕获指定类型的异常对象,进行处理

on <异常对象类型n> do <语句n> //捕获指定类型的异常对象,进行处理

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

(使用系统资源的语句)

finanlly

(释放系统资源)

end;

(3)不存在try…except…finally…end结构来既处理异常,又保护资源分配的结构,但是,try…except…end结构允许嵌套到try…finally…end结构中,从而实现既处理异常,又保护资源的分配。

(4) raise:知道一些情况不合理,直接手工弹异常对话框。如:raise 异常类.Create('异常的缺省说明');

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提供了一个很庞大的异常类体系,从大的方面可以把异常类分为运行库异 常、对象异常、组件异常三类。

3.2.1 运行库异常类(RTL Exception)

运行库异常可以分为七类,它们都定义在SysUtils库单元中。

1.I/O异常

I/O异常类EInOutError是在程序运行中试图对文件或外设进行操作失败后产生的,它从Exception派生后增加了一个公有数据成员ErrorCode,用于保存所发生错误的代码。这一成员可用于在发生I/0异常后针对不同情况采取不同的对策。

当设置编译指示{$I-}时,不产生I/0异常类而是把错误代码返回到预定义变量IOResult中。

2.堆异常

堆异常是在动态内存分配中产生的,包括两个类EOutOfMemory和EInvalidPointer,如表3-1所示。

表3-1 堆异常类及其产生原因

异常类 引发条件

EOutOfMemory 没有足够的空间用于满足所要求的内存分配

EInvalidPointer 非法指针。一般是由于程序试图去释放一个已释放的指针而引起的

3.整数异常

整数异常都是从一个EIntError类派生的,但程序运行中引发的总是它的子类:EDivByZero,ERangeError,EIntOverFlow,如表3-2所示。

表3-2 整数异常及其产生原因

异常类 引发条件

EDivByZero 试图被零除

ERangeError 整数表达式越界

EIntOverFlow 整数操作溢出

ERangeError当一个整数表达式的值超过为一个特定整数类型分配的范围时引发。比如下面一段代码将引发一个ERangeError异常。

var

SmallNumber:ShortInt;

X,Y:Integer;

begin

X:=100;

Y:=75;

SmallNumber:=X*Y;

end;

特定整数类型包括ShortInt、Byte以及与整数兼容的枚举类型、布尔类型等。例如:

type

THazard=(Safety,Marginal,Critical,Catastrophic);

var

Haz:THazard;

Item:Integer;

begin

Item:=5;

Haz:=THazard(Item);

end;

由于枚举类型越界而引发一个ERangeError异常。数组下标越界也会引发一个ERangeError异常,如:

var

Values:array[1..10]of Integer;

I:Integer;

begin

for I:=1 to 11 do

Values[I]:=I;

end;

ERangeError异常只有当范围检查打开时才会引发。这可以在代码中包含{$R+}编译指示或设置IDE Option|Project的Range_Checking Option选择框。注意,Delphi不对长字符串做范围检查。

EIntOverFlow异常类在Integer、Word、Longint三种整数类型越界时引发。如下面的代码将引发一个EIntOverFlow异常:

var

I:Integer;

a,b,c:Word;

begin

a:=10;

b:=20;

c:=1;

for I:=0 to 100 do

c:=a*b*c;

end;

EIntOverFlow异常类只有在编译选择框Option|Project|Over_Flow_Check Option选中时才产生。当关闭溢出检查,则溢出后变量的值是丢弃溢出部分后的剩余值。

4.浮点异常

浮点异常是在进行实数操作时产生的,它们都从一个EMathError类派生,但与整数异常相同,程序运行中引发的总是它的子类EInvalidOp、EZeroDivide、EOverFlow、EunderFlow (表3-3)。

表3-3 浮点异常类及其引发条件

异常类 引发条件

EInvalidOp 处理器碰到一个未定义的指令

EZeroDivide 试图被零除

EOverFlow 浮点上溢

EUnderFlow 浮点下溢

EInvalidOp最常见的引发条件是没有协处理器的机器遇到一个协处理器指令。由于在缺省情况下Delphi总是把浮点运算编译为协处理器指令,因而在386以下微机上常常会碰到这个错误。此时只需要在单元的接口部分设置全局编译指示 {$N-},选择利用运行库进行浮点运算,问题就可以解决了。

各种类型的浮点数(Real、Single、Double、Extended)越界引起同样的溢出异常。

5.类型匹配异常

类型匹配异常EInvalidCast当试图用As操作符把一个对象与另一类对

补充:软件开发 , Delphi ,
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,