第六章程序异常处理与调试技术在Delphi中有两种程序错误,一种是编译错误,在程序编辑阶段就可以由编译器发现并给出提示。
另外一种是运行错误,这类错误不能在编译阶段查出,只能在程序执行时发现,称为运行错误。
Delphi提供了一种机制来处理运行错误,保护程序的正常执行,这种机制就是异常处理。
异常处理的方法是把正常的执行程序同错误的处理程序分离开来,这样可以保证在没有错误时,程序正常执行,当发生错误时,执行错误处理部分的程序,然后程序跳出保护模块,继续执行后续的程序。
6.1 Object Pascal异常的种类异常的种类:Delphi内建的异常类,程序员自定义的异常类。
异常基类及其属性和主要方法:在Delphi中,所有异常的基类是Exception 类。
所有其他异常类都是由该类派生而来。
1. exception属性该类有两个基本属性:HelpContext和Message。
(1)Exception.HelpContext属性该属性的定义如下:▪Type ThelpContext= -MaxLongint..MaxLongint;▪Property HelpContext:ThelpContext;HelpContext是ThelpContext类的一个实例,它提供了与异常对象联系在一起的上下文相关帮助信息的序列号。
该序列号决定当发生异常时用户按F1键显示的一个异常错误的帮助信息。
(2)Exception.Message属性该属性的定义如下:property Message: string该属性存储异常发生时的错误信息。
可以通过该属性在提示错误对话框中显示错误信息字符串。
2.exception方法(1)Exception.Create方法该方法的定义形式为:Constructor Create(Const Msg: String);该方法用来产生一个带有一条简单提示信息的对话框,对话框中的提示内容由Msg提供(2)Exception.CreateFmt方法该方法的定义格式如下:Constructor CreateFmt(Const Msg:String;Const Args:Array of Const) ;该方法用来产生一个带有格式化字符串提示信息的对话框,格式化的字符串由Msg和Args数组共同提供,其中数组Args负责提供用于格式化的数值。
(3)Exception.CreatHelp方法该方法的定义格式如下:Constructor CreateHelp(Const Msg:String; AhelpContsxt:Integer) ;该方法产生一个带有一条简单提示信息和上下文帮助序列号的提示对话框。
其中Msg参数包含了显示在异常对话框中的运行错误信息。
AhelpContext参数包6.1.1 Delphi内建的异常类Delphi内建立异常类其标识符的第一个字母都是“E”,如此我们很容易就能辨认出此种类。
6.1.2自定义异常类自定义的异常类必须继承内建的Exception类,或者继承Exception的某个子类才行。
除此之外,自定义异常类的语法和自定义一般类的语法并没有不同。
6.2触发异常的方法触发异常的方法,主要可分为两种,一种是由程序系统自动触发,一种则是利用raise指令触发.6.2.1由程序系统自动触发只要属于Delphi内建类的异常产生时,程序系统就会在当下自动触发它们,并捕捉其信息,然后将异常的信息以对话框显示出来,这些是一般公认的异常状况,即使我们不对这些异常做处理,程序系统也会帮我们做处理,然后让程序再继续执行下去,这样程序就不会在当时异常中断,而出现意料之外的问题。
不过程序系统所作的只是一般的处理,通常仅是避开执行会发生异常的程序代码,而不会排除掉异常发生的原因。
故若保持原来的状态再做同样的执行操作,仍旧会触及同样的异常,却无法执行下一步的程序。
因此为了让程序执行更顺畅,并且让用户更容易使用我们所开发的应用程序。
即使是程序系统自动触发的异常,我们也应该主动去处理,设法去除导致异常的原因。
或者给予用户更明确,更人性化的提示,尽量不要让用户感到任何操怍上的困难,并且避免异常重复发生而浪费不必要的时间。
6.2.2使用raise指令触发自行触发异常的方式.使用raise指令.其语法如下:Raise 异常对象实体不要将raise指令当成一般语句使用,它必须配合异常处理语法来使用。
6.3处理异常情况专门用来处理异常情况的语句主要有两种,一种是“try_ except_end”结构,另一种则是“try_finally_end”结构。
由于Delphi在程序设计时,提供了调试器(Debugger),因此当程序执行时若发生异常状况,调试器将发挥功能,让程序在异常发生点,并且提示调试的方法,方便找出问题所在。
然而这样程序就无法如实展现异常处理的情况,而且这个应用程序若不在Delphi环境下执行,也不会有调试器存在。
因此在设计异常处理程序时,点选【Tools】|【Debugger Options】|【General】选项,然后取消【Integrated debugging】选项,这样才能看到异常处理的效果6.3.1 Try…Finally…End结构Try…Finally…End结构只需要触发异常,程序系统将自动捕捉被触发的异常,然后以信息对话框显示出异常的信息,让程序避开发生异常的程序代码,然后向下执行程序。
无论在“Try…Finaly”区内是否有异常被触发,都会接着执行“Findly…End”区的语句。
然而若是在“Try…Finally”区内有异常产生并被触发时,就会由异常发生点跳转此区域,转而执行“Finally…End”区的所有语句。
例:procedure Form1.Button1Click(Sender:TO b j e c t ) ;VarMyStringList:TStringList;beginMyStringList:= TStringList.Create;tryMyStringList.Assign(ListBox1.Items);…finallyMyStringList.Free;end;包括由程序系统自动触发以及程序员使用raise指令去触发的异常,故在本区可根据状况条件来使用Raise指令。
然而在本区使用raise指令,或者由程序系统自动触发某些异常时,程序系统并不一定会自动处理这些异常,这时程序就有可能会异常中断,因此需要“Except…End”区中捕捉异常,并且对异常作适当处理;也可仿照“Try…Finally…End”语法,在“Except…End”区对“Try…Except”区内被触发的异常作再次触发(Reraise)的操作,即再次使用Raise指令,由程序系统自动捕捉异常,以信息对话框显示出异常信息,然后让程序避开异常,而不致于中断程序。
6.3.2 “Except…End”区中的语句在“Except…End”区中,可以有多个语句,但此处主要是放置用来捕捉异常的语句,其目的是让程序仍自行捕捉异常,根据异常的类型决定要做的处理操作,而此种语句也有它特定的语法:On 异常对象标识符:类型 do //异常对象标识符可有可无语句;//(on identifier:type do statement)上述语法是表示当指定类型的异常被触发时,就执行保留字“do”后面这个语句。
反之若没有这种类型的异常被触发,则不会执行“do”后面的语句。
在捕捉异常的语句之后,还可以有一个“Else”区,在这个区域内可以有一般的语句(包括raise指令)。
若本区域内没有“Else”区域时,只要其内有捕捉异常的语句存在,就不允许有一般语句(包括raise指令);倘若本区内若有“Else”区,则除了“Else”区域之外,并不允许有一般语句存在于“Except…Else”区域,否则将导致编译错误。
6.4 程序调试Delphi提供了一个功能强大的内置调试器(Integrated Debugger) ,该调试器可以方便地查找程序中出现的运行时间错误和逻辑错误。
所谓运行时间错误是指程序能正常编译但在运行时出错。
逻辑错误是指程序设计和实现上的错误。
6.4.1调试的准备1.激活内置调试器方法是:在Delphi集成开发环境中,选中【Tools】|【Debugger Options】|【General】页的【Integrated Debugging】复选框。
默认情况下该框被选中。
2.设置编译和调试选项默认情况下,Delphi对有些错误和信息不给出调试信息。
可改变Delphi默认设置。
单击【Project】|【Options】|【Compiler】页。
(1)Runtime Errors区域Range checking:检查数组或是字符串的下标是否越界,默认时不检测。
I/O checking:检测输入输出错误,默认检测Overflow checking:整型操作溢出检测,默认不检测。
选中该复选框调试器将对整数运算是否溢出做检测,默认下不报告错误。
(2)Debugging区域设置调试的信息。
默认时几乎全部选中。
一般无须改变该区域的选项设置。
Debug information:表产生调试信息。
如果Debug Information 选中会在单元文件 (.dcu) 中放置调试信息,文件字节变大但不影响速度。
Local symbols:产生局部变量的调试信息。
Local Symbols选中会添加与所在类、过程、函数及对象方法中定义的标识符等有关调试信息。
在程序调试时调试器会使用这些信息,但这些信息不会添加到可执行文件中。
除非在【Project】|【Options】|【Linker】页面中选中【Include TD32 Debug Info】选项,选中了此选项就可以使用TD32来调试。
Reference info/Definitions only:用来产生供Code Browser, Code Explorer and Project Browser使用的标识符引用信息。
如果Reference Info和Definitions Only 都被选中,则编译器将记录标识符定义位置信息。
如果仅选中了 Reference Info,表示编译器不仅记录标识符定义的位置,同时将记录标识符被引用的信息。
如果不选中Debug Information 和 Local Symbols 选项,仅选中该选项将不起作用。
Assertions:产生断言的调试代码。
Use Debug DCUs:使用连接的Dcu文件作为调试路径。
必须在【Tools】|【Debugger Options】|【General】页中指定调试文件的路径。