Object Pascal 语法之异常处理
http://www.cnblogs.com/spider518/archive/2010/12/30/1921298.html
结构化异常处理(SHE)是一种处理错误的手段,使得应用程序能够从致命的错误中很好地恢复。
异常的来源
在Delphi的应用程序中,下列的情况都比较有可能产生异常。
(1)文件处理
(2)内存分配
(3)Windows资源
(4)运行时创建对象和窗体
(5)硬件和操作系统冲突
在早期的Delphi 中,异常是由Object Pascal 语言来处理的;从Delphi 2 开始,异常成为Win32 API 的一部分。用Object Pascal 来处理异常比较简单,因为异常中包含了错误的位置和特征性信息,这使得异常的使用和实现与普通的类一样。当一个错误或一些其他事件中止了程序的正常运行,系统就会抛出一个异常。
Delphi 中包含了一些预定义的通用的程序错误异常,例如内存不足、被零除、数字上溢和下溢以及文件的输入输出错误,程序开发人员可以定义自己的异常类来适应程序的需要。通过Delphi 的异常处理机制,可以捕获这个异常并进行处理。异常实际上可以是一些对象,也可以是任何类的一个实例。通常程序开发人员总是自己定义一个从Exception 类派生出的异常类,其定义的方法与普通类的定义方法基本一致。Exception 类是在SysUtils 单元中定义的。如果一个程序的Uses 语句中包含了SysUtils 单元,发生运行错误时就会抛出一个异常。可以利用类的继承性将一组异常组合成一个系列。例如在SysUtils 单元中就定义了有关数学方面的一组异常类:
type
EMathError = class(Exception);
EInvalidOp = class(EMathError);
EZeroDivide = class(EMathError);
EOverflow = class(EMathError);
EUnderflow = class(EMathError);
有时在异常类中还定义一些字段、属性和方法,通过它们可以传达一些错误信息。例如:
type
EInOutError = class(Exception)
ErrorCode: Integer;
end;
在Try...Except 语句中可以进行抛出异常和处理异常的工作。Try...Except 的一般形式如下:
try
Statements1;
except
on Exception1 do HandleStatements1;
on Exception2 do HandleStatements2;
...
on ExceptionN do HandleStatementsN;
else
Statements2;
end.
对于有些操作,在异常处理部分要进行,在正常情况下也要进行。例如在正常情况下,使用完文件之后关闭文件;如果在对文件操作的过程中出现了异常,也需要关闭已经打开的文件。这时,就可以把关闭文件的过程放在Try...Finally 语句的Finally 部分,不管Try 部分的操作是否正常,都要进行Finally 部分的操作。
通常Try...Finally 语句的形式如下:
try
statementList1
finally
statementList2
end
可以看到,Try...Finally 语句的用法与Try...Except 语句的用法很相似。StatementList1 可以为简单语句,也可以为复合语句。如果在StatementList1 中抛出了异常,程序立即转到Finally 部分;如果在StatementList1 中执行了Exit、Break 或Continue 过程而导致程序的控制离开StatementList1 部分时,程序也会跳转到Finally 部分;如果在Try 部分正常执行完毕,接着执行的还是Finally 部分。
下面的例子介绍了在文件输入/输出时, 怎样用异常处理。可以区分与Try...Except 语句和Try...Finally 语句的用法。
program Project1; uses
Classes,Dialogs,SysUtils; {$APPTYPE CONSOLE} var
F:TextFile;
S:String; begin
AssignFile(F,'f1.txt');
try
reset(F);
try
readln(F,s);
finally
CloseFile(F);
end;
except
on EinOutError do
ShowMessage('Error in FileIO');
end;
end.
内层的Try...Finally 代码块用来确保文件总是关闭的,而不管是否发生了异常。这段代码的执行过程是:先执行Try 与Finally 之间的代码;如果执行完毕或出现异常,就执行Finally 与End 之间的代码;如果确实有异常发生,就跳到外层的异常处理块。这样,即使出现异常,文件也总是关闭的,并且异常总能得到处理。
注意:在Try...Finally 块中,Finally 后面的语句不管有没有异常都被执行。因此,Finally 后面的语句不能以发生异常为前提。另外,由于Finally 后面的语句并没有处理异常,因此,异常被传递到下一层的异常处理块。外层的Try...Except 块用于处理程序中发生的异常。在Finally 中关闭文件,并且在Except 块显示一个信息,告诉用户发生了I/O 错误。这种异常处理机制比传统的错误处理方式优越,它使得错误检测代码从错误纠正代码中分离出来。这是一件好事,它会使程序更可读,使得开发人员能够集中处理程序的其他代码。
使用Try...Finally 代码块,但不捕捉特定种类的异常是有一定意义的。当代码中使用Try...Finally块的时候,意味着程序并不关心是否发生异常,而只是想最终总是能进行某项任务。Finally 块最适合于释放先前分配的资源(例如文件或Windows 资源),因为它总是执行的(即使发生了错误)。不过,很多情况下,可能需要对特定的异常做特定的处理,这时候就要用Try...Except 块来捕捉特定的异常。
例如:
Program Project1;
{$APPTYPE CONSOLE} uses
SysUtils,Dialogs; var
R1,R2:double; begin
while True do begin
try
write('Enter a real number: ');
readln(R1);
write('Enter another real number: ');
readln(R2);
writeln('The first number divided by the Second is: ',(R1/R2):5:3);
except
on EInOutError do
ShowMessage('It is not a valid number! ');
on EZeroDivide do
ShowMessage('Can not divide by zero! ');
end;
end;
end.
尽管在Try...Except 块中可以捕捉特定的异常,也可以用Try...Except...Else 结构来捕捉其他异常。当使用Try...Except...Else 结构的时候,应当明白Else 部分会捕捉所有的异常,包括那些并没有预料到的异常,例如内存不足或其他运行期异常。因此,使用Else 部分时要小心,能不用则不用。当进入不合格的异常处理过程中时,应当触发这个异常。
不存在try…except…finally…end结构来既处理异常,又保护资源分配的结构,但是,try…except…end结构允许嵌套到try…finally…end结构中,从而实现既处理异常,又保护资源的分配。
使用Raise 语句调用一个异常类的构造函数,并抛出一个异常。例如:raise EInOutError.Create;
通常,Raise 语句的形式如下:
raise object at address
其中Object 和At Address 是可选项,Address 通常是一个指向过程或函数的指针。一个抛出的异常在处理后自动地被删除,一般不需要主动地删除一个异常对象。
异常是一种特殊的对象实例,它在异常发生时才实例化,在异常被处理后自动删除。异常对象的基类被称为Exception。在异常对象中最重要的元素是Message 属性,它是一个字符串,它提供了对异常的解释,由Message所提供的信息是根据产生的异常来决定的。
注意:如果定义自己的异常对象,一定是要从一个已知的异常对象例如Exception 或它的派生类派生出来的,因为这样,通用的异常处理过程才能捕捉这个异常。当在Except 块中处理一个特定的异常时,可能会捕捉到该异常的派生异常。例如EMathError 是所有与数学有关的异常(例如EZeroDivide、EOverflow)的祖先。凡是没有显式地处理的异常最终将被传送到Delphi 运行期库中的默认处理过程并在此得到处理。
Exception异常类
Exception是所有异常类的基类,它并不是以’T'开头,而是以’E'开头,它的派生类也是以’E'开头的。Exception类定义于SysUtils单元中。Exception类最常用的方法是Create方法:
Constructor Create(const Msg:string);
Exception.Create(‘我自己创建的异常!’);
该方法用于创建一个异常类的实例,也可以显示错误信息,也可直接用这个方法提交一个异常
raise Exception.Create(‘我抛出的异常!’);
例:
try
raise Exception.Create('我抛出的异常!');
except
on E: Exception do
showmessage('异常类名称:' + E.ClassName + ## + '异常信息:' + E.Message);
end;
Delphi7内置的异常类
Delphi7根据异常现象的类型定义了相应的异常类,这些异常类又称为Delphi7内置的异常类。具体分为运行时库异常类、对象异常类和组件异常类三大类.
运行时库异常类(RTL)
运行时库异常类可分为以下几种:
- 1 整数计算异常
- 2 浮点计算异常
- 3 硬件异常
- 4 堆异常
- 5 输入输出异常(I/O异常)
- 6 字符转换异常
- 7 类型转换异常
- 8 哑异常
整数计算异常
EIntError 整数计算异常(基类)
EDivByZero 整数除0溢处
EIntOverFlow 整数溢出
ERangeError 整数越界
浮点计算异常
EMathError 浮点计算异常(基类)
EInvalidOp 无效浮点操作指令
Eoverflow 浮点操作上溢
Eunderflow 浮点操作下溢
EZeroDivide 浮点计算除0
硬件异常
EProcessorException 硬件异常(基类)
ESingleStep 应用程序产生单步中断
Ebreakpoint 应用程序产生断点中断
Efault 故障(继承EProcessorException,也是基类)
EStackFault 对处理器栈段的非法访问
EPageFault 内存管理器无法正确使用交换文件
EGPFault 保护性错误,一般由未初始化指针或对象造成
EInvalidOpCode 处理器遇到未定义指令
堆异常
EOutOfMemory 堆中没有足够的内存完成操作
EInvalidPointer 试图访问一个堆外的指针
I/O异常
EInOutError DOS输入/输出错误
字符转换异常
EConvertError 数字到字符串或字符串到数
字转换错误
类型转换异常
EInvalidCast 类型转换异常
哑异常
EAbort 调用Abort产生,不显示错误提示框
对象异常类
对象异常类是针对非组件对象引发的异常而定义的.
对象异常类包括:
- 1 流异常类
- 2 打印异常类
- 3 图形异常类
- 4 字符串链表异常类
流异常类
流异常是指在程序中进行与流相关的操作时产生的异常.流异常类的基类是EStreamError,其他流异常类都直接或间接从它派生.
派生关系见书48页图
打印异常
打印异常是由于应用程序向不存在的打印机发送打印命令或由于某种原因打印工作无法送到打印机时引发的.
打印异常类为Eprinter,定义于Printers单元
图形异常
图形异常主要包括EInvalidGraphic 和 EInvalidGraphicOperation两个类均定义于Graphics单元
EInvalidGraphic异常满足下列情况之一时引发:
- 当应用程序试图向一个并不包含合法的位图,图象,元文件或用户自定义图形类型的文件中装入图象时.
- 当应用程序试图装入不可识别扩展名的文件时
- 当图象与LoadFromClipboardFormat或SaveToClipboardFormat中的格式不匹配时.
- 当应用程序试图将图象的PixelFormat设为不支持的值
EInvalidGraphicOperation异常在满足下列条件之一时发生:
- 应用程序访问图象中不存在的扫描线时.
- 应用程序不能成功写入图象时.
- 应用程序在画布未处于有效状态时进行绘制.
- 应用程序装入未知或不支持的图象格式时.
- 应用程序将图象的PixelFormat设为不支持的值时
- 不能分配该操作的句柄时.
字符串链表异常
字符串链表异常是由于用户对字符串链表进行非法操作时引发的。包括EStringListError,EListError等.由于许多部件都有一个Tstrings抽象类的属性(如Tiistbox组件的Items属性等),因而字符串链表异常在组件编程中很重要.
EStringListError一般在字符串链表越界时产生.而EListError异常通常在以下情况下发生:
当索引项超出链表范围时
当字符串链表的Duplicates属性设置为dupError
同时应用程序试图加入一个重复的字符串时.
当向已排序的字符串链表中插入字符串时.
组件异常类
组件异常类用于响应组件异常,组件异常是由于对VCL组件进行操作时,违反了组件的使用规则及其特征而引发的,可分为两大类: 用组件异常、专用组件异常。
通用组件异常
常见的有非法操作异常,组件异常和资源不足异常三种类型,对应于EInvalidOpetation,EComponentError和EOutOfResource异常类.
引发非法操作异常的原因有:
应用程序试图对Parent属性为nil的组件进行一些需要窗口句柄的操作.
试图对窗体拖放操作.
引发组件异常的原因有:
Delphi不能注册某个组件
应用程序不能重命名某个组件
资源不足异常被引发是由于当应用程序试图创建窗口句柄而操作系统没有多余的句柄可分配
专用组件异常:许多组件都定义了相应的组件异常类.
列出几个典型的组件异常类:
EMenuError异常,菜单异常,是由于程序对菜单的非法操作而引发的.定义于Memus单元
EInvalidGridOperation异常.非法的网格操作,如试图引用一个不存在的网格单元时引发.定义于Grids单元
EDatabaseError异常.数据库异常是由于对数据库的非法操作引起的.
用户自定义异常类
创建用户自定义异常类的方法
选择Exception作为基类,按照定义类的一般方法,建立自定义的异常类就可以了.
如:
type
EMyException = class(Exception)
//需要定义属性或方法时,写在此处即可
end;抛出自定义异常
异常的调试
在Delphi IDE中,解除“Debugger Options”(可以使用菜单Tools—>Debugger Options…进行访问)中的Integrated Debugging复选框的勾选状态可以进行异常的调试。
Object Pascal 语法之异常处理的更多相关文章
- Object Pascal中文手册 经典教程
Object Pascal 参考手册 (Ver 0.1)ezdelphi@hotmail.com OverviewOverview(概述)Using object pascal(使用 object p ...
- 终于懂了:Delphi的函数名不是地址,取地址必须遵守Object Pascal的语法(Delphi和C的类比:指针、字符串、函数指针、内存分配等)good
这点是与C语言不一样的地方,以前我一直都没有明白这一点,所以总是不明白:函数地址再取地址算怎么回事? ------------------------------------------------- ...
- Object Pascal 过程与函数
过程与函数 过程与函数是实现一定功能的语句块,是程序中的特定功能单元.可以在程序的其他地方被调用,也可以进行递归调用.过程与函数的区别在于过程没有返回值,而函数有返回值. 1.过程与函数的定义 过程与 ...
- Object Pascal 数据类型
数据类型与定义变量 Object Pascal 语言的最大特点是对数据类型的要求非常严谨.传递给过程或函数的参数值必须与形参的类型一致.在Object Pascal 语言中不会看到像C 语言编译器提 ...
- Object Pascal 语言基础
Delphi 是以Object Pascal 语言为基础的可视化开发工具,所以要学好Delphi,首先要掌握的就是Object Pascal 语言.Object Pascal语言是Pascal之父在1 ...
- Object Pascal对象模型中构造函数之研究
http://www.delphi2007.net/delphiblog/html/delphi_2004511950333715.html 前言 近期,一直在使用 C++ 与 Object Pasc ...
- Object Pascal 运算符
Object Pascal 的运算符 运算符是程序代码中对各种类型的数据进行计算的符号,通常分为算数运算符.逻辑运算符.比较运算符和按位运算符. 1.算术运算符Object Pascal ...
- Object Pascal 面向对象的特性
2 面向对象的特性 在软件系统开发过程中,结构分析技术和结构设计技术具有很多优点,但同时也存在着许多难以克服的缺点.因为结构分析技术和结构设计技术是围绕着实现处理功能来构造系统的,而在系统维护和软件升 ...
- Delphi APP 開發入門(六)Object Pascal 語法初探
Delphi APP 開發入門(六)Object Pascal 語法初探 分享: Share on facebookShare on twitterShare on google_plusone_sh ...
随机推荐
- syntactically incorrect() 404
遇到这个错误就来记录一下吧. 这个错误是springMVC报出的错误.大致的意思就是form传值的类型和controller中的参数不符. 有可能是名字错误,有可能是类型不对.比如前面你传来的是 p ...
- C#递归1~100的累加
public static int Accum(int m, int n) { //对于接受的参数,要考虑m >n,m=n,m<n三种情况. if (m < n) { return ...
- ubuntu /etc/profile和/etc/environment的比较
先将export LANG=zh_CN加入/etc/profile ,退出系统重新登录,登录提示显示英文. 将/etc/profile 中的export LANG=zh_CN删除,将LNAG=zh_C ...
- laravel框架总结(一) -- 请求和响应
一.laravel请求 1.获取请求 1>获取请求的 URI path 方法会返回请求的 URI.所以,如果接收到的请求目标是 http://domain.com/foo/bar,那么 path ...
- Undefined symbols for architectureIOS
IOS问题解决. 现在进行老项目的编译,发现不能编译. 经过各种盲目查询,找个几个方案. 1.builde setting修改编译方式. 2.Builde Phases(修改). 2.1.库. 2.1 ...
- Path文件操作实例
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="AddProduct.asp ...
- 【leetcode❤python】 36. Valid Sudoku
#-*- coding: UTF-8 -*-#特定的九个格内1-9的个数至多为1#依次检查每行,每列,每个子九宫格是否出现重复元素,如果出现返回false,否则返回true.class Solutio ...
- vi及缩进设置
set autoindent,把当前行的对起格式应用到下一行: set smartindent,智能的选择对起方式: set tabstop=4,设置tab键为4个空格: set shiftwidth ...
- JAVAWEB安全开发
晚上在看司马的博客,看到一篇关于JAVA安全的,基础的,蛮不错的,给大家分享下 文章来源是司马的博客:http://www.nxadmin.com/web/1332.html ============ ...
- Nmap使用指南(1)
Nmap是一款开源免费的网络发现(Network Discovery)和安全审计(Security Auditing)工具.软件名字Nmap是Network Mapper的简称.Nmap最初是由Fyo ...