DELPHI 异常处理 详解(全)
- 格式:pdf
- 大小:149.37 KB
- 文档页数:9
第六章程序异常处理与调试技术在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负责提供用于格式化的数值。
Delphi异常处理机制Delphi的异常处理⽅式有两种:try...except...end;try...finally...end;。
try...except主要⽤于捕获异常,只有出现异常的时候才会执⾏except部分。
try...finally主要⽤于资源释放,⽆论try语句块是否有异常都会执⾏finally语句块。
如下⾯的代码:tryraise exception.create('发现异常'); //在try语句块中抛出⼀个异常excepton e:Exception do//捕获异常beginshowMessage(e.message);end;end;⽤try..except是不会出现异常提⽰信息的对话框,需要⾃⼰主动去show出异常信息。
⽽try..finally.则会出现异常提⽰信息。
try..except和try..finally可以相互嵌套。
使⽤on e:Exception do可以精确处理特定的异常。
Exception是所有异常类的基类,Delphi内部就定义了处理常见异常的异常类(在SysUtils单元中),也可以从Exception继承定义⾃⼰的异常类使⽤raise语句可以抛出⼀个异常:EMyException=class(Exception)end;trytryraise EMyException.Create('我⾃⼰的异常');excepton e:EMyException doshowMessage(e.message);end;finallyshowMessage('我始终被执⾏');end。
异常处理与程序调试(三)Delphi教程12.4.3 断点的使用12.4.3.1 设置断点设置断点首先在Code Editor中选定你想设置断点的代码行,而后进行如下的任一种操作:● 单击选定代码行左边的空白● 按F5 ● 选择Code Editor加速菜单的Toggle BreakPoint项● 选择Run|Add Breadpoint打开断点编辑对话框(Edit BreakPoint Dialog Box),而后选择New去确认一个新的断点设置或选择Modify去对一个存在的断点进行修改● 从BreakPoint List加速菜单中选择Add BreakPoint项断点必须位于可执行代码行上,凡设置在注释、空白行、变量说明上的都是无效的。
另外,断点既可以在设计状态下设置也可以在运行调试状态下设置。
12.4.3.2 断点的操作断点列表窗口(BreakPoint List Window)列出了所有断点所在的源文件名、行号、条件以及已通过的次数。
如果一个断点非法或失去功能,则在列表窗口中变灰。
断点列表窗口可以通过选择View|BreakPoint菜单打开。
断点列表窗口是断点操作的基础。
1.显示和编辑断点处的代码利用断点列表窗口可以快速找到断点在源代码中的位置。
首先选定断点而后从加速菜单中选择View Source或Edit Source。
此时Code Editor更新,显示该断点位置处的代码。
如果选择的是View Source,则断点列表窗口仍保持活动;如果选择的是Edit Source,则Code Editor获得输入焦点,可以在断点位置修改源代码。
2.断点功能的丧失和恢复使断点失去功能可以使断点从当前程序运行中隐藏起来。
假如你定义了一个断点当前并不需要,但可能在以后使用,则这一功能是很有用的。
断点列表窗口加速菜单的Disable BreakPoint和Disable All BreakPoints项可以使当前选中断点或所有断点失去功能。
delphi字符串处理中的怪异现象与处理⽅式1,怪异现象:字符串相加操作不正常!以上代码,明显输出字符串应含有后缀“.jpg”,但实际输出却不含后缀(如下),字符串加法操作似乎不起作⽤了!采⽤showMessage进⾏输出,看看结果如何?结果仍是不显⽰字符串后缀,但可以看到字符串偏左显⽰,似乎后⾯还有很多不可见字符。
2,怪异原因:字符串中含有\0,即字符串终⽌符以上现象已经看出,字符串加法失效的原因可能是含有某些不可见字符,那到底是什么字符呢?回到这些字符串产⽣的源头,即下⾯由字节数组转换成字符串函数:显然,此函数未考虑len长度以内可能含有的\0字符,如果buffer中len长度以内含有\0字符,那么这些\0字符也会被复制进result字符串中,造成后续字符串加法“失效”。
3,解决⽅案:修改函数将函数修改如下,判断逐字节判断buffer,遇到\0就返回,这样转换的字符串就不含\0了。
问题解决。
//字节转换为字符串 $D4 $C1--> '粤'function BytesToString(buffer: Array of byte; offset:integer; len: integer): string;varstr: string;i : Integer;beginSetLength(str, len);for i:=0 to len-1 dobeginif buffer[offset-1+i]=0 then break; //遇到ASCII 0不再复制!Move(buffer[offset-1+i], str[1+i], 1);//注意,这⾥是从str[1]开始复制的end;//Move(buffer[offset-1], str[1], len);//注意,这⾥是从str[1]开始复制的//ShowMessage (str);SetLength(str, i);result := str;end;以上这篇delphi 字符串处理中的怪异现象与处理⽅式就是⼩编分享给⼤家的全部内容了,希望能给⼤家⼀个参考,也希望⼤家多多⽀持。
一、异常的来源在Delphi的应用程序中,下列的情况都比较有可能产生异常。
(1)文件处理(2)内存分配(3)Windows 资源(4)运行时创建对象和窗体(5)硬件和操作系统冲突二、异常的处理(1)try…except…end;在try体内的代码发生异常时,系统将转向except部分进行异常的处理。
这是Delphi处理异常的最基本的方式之一。
(2)try…finally…end;这种异常处理结构一般用于保护Windows的资源分配等方面,它确保了无论try体内的代码是否发生异常,都需要由系统进行最后的统一处理的一些Windows对象的正确处理。
和try…except…end不同,该结构的finally部分总被执行。
(3)不存在try…except…finally…end结构来既处理异常,又保护资源分配的结构,但是,try…except…end结构允许嵌套到try…finally…end结构中,从而实现既处理异常,又保护资源的分配。
三、异常的精确处理(1)定义一个异常。
在Delphi中,每个异常都是Exception[1]类的一个派生类[2]。
因此,定义一个异常就是定义一个Exception类的派生类。
type EMyException =class(Exception;当然,基类可以是Exception或者Exception的任何一个任何层次的派生类。
(2)在程序中抛出一个异常。
根据不同的情况抛出异常是使用异常的最基本的模式。
在Delphi中,由raise语句来实现。
【语法】raise 异常类.Create(…异常的缺省说明‟; (3)在try…except…end 中更加精确的捕捉异常。
使用on E:异常类do…结构可以在do体内处理特定异常类所抛出的异常。
四、异常的调试在Delphi IDE中,解除“Debugger Options”(可以使用菜单Tools—>Debugger Options…进行访问)中的Integrated Debugging复选框的勾选状态可以进行异常的调试。
Delphi异常处理与程序调试(2)12.3 异常响应异常响应为开发者提供了一个按自己的需要进行异常处理的机制。
try …except …end形成了一个异常响应保护块。
与finally不同的是:正常情况下except 后面的语句并不被执行,而当异常发生时程序自动跳到except,进入异常响应处理模块。
当异常被响应后异常类自动清除。
下面的例子表示了文件打开、删除过程中发生异常时的处理情况:uses Dialogs;varF: Textfile;beginOpenDialog1.Title := 'Delete File';if OpenDialog1.Execute thenbeginAssignFile(F, OpenDialog1.FileName);tryReset(F);if MessageDlg('Erase ' +OpenDialog1.FileName + '?',mtConfirmation, [mbYes, mbNo], 0) = mrYes thenbeginSystem.CloseFile(F);Erase(F);end;excepton EInOutError doMessageDlg('File I/O error.', mtError, [mbOk], 0);on EAccessDenied doMessageDlg('File access denied.', mtError, [mbOk], 0);end;end;end.保留字on…do用于判断异常类型。
必须注意的是:except后面的语句必须包含在某一个on…do模块中,而不能单独存在。
这又是同finally不同的一个地方。
12.3.1 使用异常实例上面所使用的异常响应方法可总结为如下的形式:on ExceptionType do{响应某一类的异常}这种方法唯一使用的信息是异常的类型。
异常和错误处理(基于Delphi/VCL)有人在看了我的“如何将界面代码和功能代码分离(基于Delphi/VCL)”之后,提到一个问题,就是如何对服务端的类的错误进行处理。
在基于函数的结构中,我们一般使用函数返回值来标明函数是否成功执行,并给出错误类型等信息。
于是就会有如下形式的代码:RetVal := SomeFunctionToOpenFile();if RetVal = E_SUCCESSED then......else if RetVal = E_FILENOTFOUND then......else if RetVal = E_FILEFORMATERR then......else then......使用返回错误代码的方法是非常普遍的,但是使用这样的方法存在2个问题:1、造成冗长、繁杂的分支结构(大量的if或case语句),使得控制流程变得复杂2、可能会有没有被处理的错误(函数调用者如果不判断返回值的话)而异常是对于错误处理的面向对象的解决方案。
它可以报告错误,但需要知道的是,并非由于错误而引发了异常,而仅仅是因为使用了raise。
在Object Pascal中,抛出异常使用的是raise保留字。
在任何时候(即使没有错误发生),raise都将会导致异常的发生。
异常可以使得代码从异常发生处立刻返回,从而保护其下面的敏感代码不会得到执行。
通过异常从函数返回和正常从函数返回(执行到函数末尾或执行了Exit)对于抛出异常的函数本身来说是没有什么区别的。
区别在于调用者处,通过异常返回后,执行权会被调用者的try...e xcept块所捕获(如果它们存在的话)。
如果调用者处没有try...except块的话,将不会继续执行后续语句,而是返回更上层的调用者,直至找到能够处理该异常的try...except块。
异常被处理后,将继续执行try...except块之后的语句,控制权就被留在了处理异常的这一层。
2. 响应异常和try ... except ... end;语句该语句结构提供了一个可以根据需要进行自定的异常处理的机制。
其一般格式如下: try // 以下为保护代码块 if <异常条件> raise <异常对象> except // 以下为异常处理块 on <异常类1> do <处理过程1或语句1> // 捕获异常为异常类1的处理 on <异常类2> do <处理过程2或语句2> // 捕获异常为异常类2的处理on .….. else <其他处理过程或语句> // 该子句可以缺省end;
三、自定义异常类及其应用通过继承类exception,可以自定义新的异常类。
定义一个新异常的形式如下: type 异常类名 = class(Exception; 或者如下: type 异常类名 = class(Exception 类成员 // 数据域或方法 ... end;。
Science &Technology Vision科技视界0引言软件无论在测试中,还是常规运行时,都不可避免会发生由于软件设计、编码或操作人员非法操作,或者是数据库、网络线路等软硬件错误而引发应用程序异常。
在Delphi 的集成开发环境(IDE)中提供了一个完善的内置调试器,可以帮助你发现大部分程序错误。
但并不是所有的错误都可以被发现,而且当程序涉及到与外设的数据交换或操作外设,如要求用户输入、读写磁盘等时,错误的发生是程序无法控制的,如输入非法字符、磁盘不能读写等。
这些情况不仅回导致应用程序异常终止而且可能引起系统的崩溃。
针对这些问题,Delphi 同时提供了一套强大的异常处理机制。
巧妙地利用它,可以使你的程序更为强健,使用更为友好。
现本人结合实际,详细讨论Delphi 中异常处理及其实现方法。
1Delphi 异常处理机制Delphi 异常处理机制建立在保护块(Protected Blocks)的概念上。
所谓保护块是用保留字try 和end 封装的一段代码。
保护块的作用是当应用程序发生错误时自动创建一个相应的异常类(Exception)。
程序可以捕获并处理这个异常类,以确保程序的正常结束以及资源的释放和数据不受破坏。
如果程序不进行处理,则系统会自动提供一个消息框,告诉用户用处产生的原因,并终止程序的执行。
1.1异常类异常类是Delphi 异常处理机制的核心,也是Delphi 异常处理的主要特色。
Delphi 通过异常类Exception 来实现异常处理机制。
Exception 类是其它所有异常类的基类,其它异常类均是Exception 类的子类。
Exception 类定义在单元SysUtil 中,定义如下(对于不常用的成员没有列出):{SysUtil 单元中}Exception=class(Tobject)PrivateFmessage:Pstring;FhelpContext:Longint;Function GetMessage:String;Procedure SetMessage(const Value;String);Publicconstructor Create(const Msg:String);constructor CreateFmt (const Msg:String;const Args:array ofconst);…destructor Destroy;override;property HelpContext:Longint;property Message:String;property MessagePrt:Pstring;end;当然,用户也可以象定义其它类一样来定义自己的异常类。
DELPHI基础教程:异常处理与程序调试(二)[2]下面的代码同时使用了异常响应和异常保护异常响应用于设置变量的值异常保护用于释放资源当异常响应结束时利用raise重引发一个当前异常varAPointer: Pointer ;AInt ADiv: Integer;beginADiv := ;GetMem ( APointer )trytryAInt := div ADiv ;excepton EDivByZero dobeginAInt := ;raise;end;end;finallyFreeMem ( APointer )end;end;上面一段代码体现了异常处理的嵌套异常保护异常响应可以单独嵌套也可以如上例所示的那样相互嵌套自定义异常类的应用利用Delphi的异常类机制我们可以定义自己的异常类来处理程序执行中的异常情况同标准异常不同的是这种异常情况并不是相对于系统的正常运行而是应用程序的预设定状态比如输入一个非法的口令输入数据值超出设定范围计算结果偏离预计值等等使用自定义异常需要自己定义一个异常对象类自己引发一个异常定义异常对象类异常是对象所以定义一类新的异常同定义一个新的对象类型并无太大区别由于缺省异常处理只处理从Exception或Exception子类继承的对象因而自定义异常类应该作为Exception或其它标准异常类的子类这样假如在一个模块中引发了一个新定义的异常而这个模块并没有包含对应的异常响应则缺省异常处理机制将响应该异常显示一个包含异常类名称和错误信息的消息框下面是一个异常类的定义typeEMyException = Class(Exception) ;自引发异常引发一个异常调用保留字raise 后边跟一个异常类的实例假如定义typeEPasswordInvalid = Class(Exception)则在程序中如下的语句将引发一个EPasswordInvalid异常If Password <> CorrectPassword thenraise EPasswordInvalid Create( Incorrect Password entered )异常产生时把System库单元中定义的变量ErrorAddr的值置为应用程序产生异常处的地址在你的异常处理过程中可以引用ErrorAddr的值在自己引发一个异常时同样可以为ErrorAddr分配一个值为异常分配一个错误地址需要使用保留字at 使用格式如下raise EInstance at Address_Expession;自定义异常的应用举例下面我们给出一个利用自定义异常编程的完整实例两个标签框(Label Label )标示对应编辑框的功能编辑框PassWord和InputEdit用于输入口令和数字程序启动时Label InputEdit不可见当在PassWord中输入正确的口令时Label InputBox出现在屏幕上此时Label PassWord隐藏设计时令Label InputEdit的Visible属性为False 通过设置PassWord的PassWordChar可以确定输入口令时回显在屏幕上的字符自定义异常EInvalidPassWord和EInvalidInput分别用于表示输入的口令非法和数字非法它们都是自定义异常EInValidation的子类而EInValidation直接从Exception异常类派生下面是三个异常类的定义typeEInValidation = class(Exception)publicErrorCode: Integer;constructor Create(Const Msg: String;ErrorNum: Integer)end;EInvalidPassWord = class(EInValidation)publicconstructor Create;end;EInvalidInput = class(EInValidation)publicconstructor Create(ErrorNum: Integer)end;EInValidation增加了一个公有成员ErrorCode来保存错误代码错误代码的增加提供了很大的编程灵活性对于异常类可以根据错误代码提供不同的错误信息对于使用者可以通过截取错误代码在try…except模块之外来处理异常从以上定义可以发现 EInvalidPassWord和EInvalidInput的构造函数参数表中没有表示错误信息的参数事实上它们保存在构造函数内部下面是三个自定义异常类构造函数的实现代码constructor EInValidation Create(Const Msg: String; ErrorNum: Integer)begininherited Create(Msg)ErrorCode := ErrorNum;end;constructor EInValidPassWord Create;begininherited Create( Invalid Password Entered )end;constructor EInValidInput Create(ErrorNum: Integer)varMsg: String;begincase ErrorNum of:Msg := Can not convert String to Number ;:Msg := Number is out of Range ;elseMsg := Input is Invalid ;end;inherited Create(Msg ErrorNum)end;对于EInvalidInput ErrorCode= 表示输入的不是纯数字序列而ErrorCode= 表示输入数值越界lishixinzhi/Article/program/Delphi/201311/25189。
Delphi关于数据库处理的一些出错及解决
1 无法为更新定位行。
一些值可能已在最后一次读取后已更改。
Delphi在使用ADO操作sql server数据库时,经常会出现“无法为更新定位行。
一些值可能已在最后一次读取后已更改。
”的错误,
原因是表没有主键,无法重新定位。
应该为每个表都设置一个主键,并且,在联合查询的时候不要有重复的键名.
比如a表和b表的主键都是"ID"那么保留一个主键就可以了
因为数据库存在默认值,在第一次append的时候,数据库自动修改了部分列,所以客户端无法定位。
2 DELPHI中新插入一条记录,紧接着删除该记录,提示"无法为更新定位行。
一些值可能已在最后一次读取后已更改" 引发一个EOleException错误。
分析:插入记录后记录集的指真eof为true,所以需要重新定位。
同一个表,如果你打开了某条记录,别人也同时打开了这条记录,并且更改了这条记录的内容,你再保存的话就会给出这个提示。
反正不能同时更改同一条记录的同一个字段!
A和B都打开了同一个数据表,此时A更改了表并保存了,但B也更改了,但B更改的源数据还是A没更改之前的,所以B只能放弃此次修改的结果,或者B在更改之前再次读一遍。
Delphi_异常处理 _详解 (全 .txtDelphi 异常处理详解[1] Exception类的定义在 SysUtils 单元中。
[2] Delphi也支持不从 Exception 继承的异常类,但是我觉得这么做并不十分的明智。
一、异常的来源在 Delphi 的应用程序中,下列的情况都比较有可能产生异常。
(1文件处理(2内存分配(3 Windows 资源(4运行时创建对象和窗体(5硬件和操作系统冲突二、异常的处理(1 t ry…except…end;在 try 体内的代码发生异常时,系统将转向 except 部分进行异常的处理。
这是Delphi 处理异常的最基本的方式之一。
(2 try…finally…end;这种异常处理结构一般用于保护 Windows 的资源分配等方面, 它确保了无论try 体内的代码是否发生异常,都需要由系统进行最后的统一处理的一些 Windows 对象的正确处理。
和try…except…end 不同,该结构的 finally 部分总被执行。
(3不存在try…except…finally…end 结构来既处理异常,又保护资源分配的结构,但是, try…except…end 结构允许嵌套到try…finally…end 结构中,从而实现既处理异常,又保护资源的分配。
三、异常的精确处理(1定义一个异常。
在 Delphi 中,每个异常都是 Exception[1]类的一个派生类 [2]。
因此,定义一个异常就是定义一个 Exception 类的派生类。
type EMyException = class(Exception;当然,基类可以是 Exception 或者 Exception 的任何一个任何层次的派生类。
(2在程序中抛出一个异常。
根据不同的情况抛出异常是使用异常的最基本的模式。
在 Delphi 中,由 raise 语句来实现。
【语法】 raise 异常类.Create(… 异常的缺省说明‟;(3在try…except…end 中更加精确的捕捉异常。
delphi的异常及事务保护的常见问题浅析、exit方法原以为exit方法执行后,会马上退出过程,但是真正做了一个例子来测试后,才让我改变了想法。
请看下面这个例子,flag最后被赋值为´c´。
======================================================== ========================================varflag: string;begintryflag := ´a´;exit;flag := ´b´;finallyflag := ´c´;end;flag := ´d´;end;======================================================== ========================================分析:不论try子句如何结束,finally 子句总是被执行。
(多谢ylmg网友)2、一个能让整个系统停止运作的小问题在数据库系统设计中,经常使用事务操作来保证数据的完整性,但是设计不当,却容易产生比较大的影响,下面举个例子说明虽然数据完整性保证了,但是可能令到系统完全停止运作:======================================================= =========================================adoconnection1.begintrans;try...if application.messagebox(´是否确定删除?´, ´询问´,mb_yesno+mb_iconquestion)<>idyes then //(1)begin...end;application.messagebox(´操作失败´, ´警告´, mb_ok); //(2)exceptapplication.messagebox(´操作失败´, ´警告´, mb_ok); //(3)adoconnection1.rollbacktrans;end;====================================================== ==========================================分析:上面代码中的问题都是由于(1)、(2)、(3)的application.messagebox引起,但是引起问题的并不是application.messagebox本身,而是它将程序挂起,需要用户干预后,才继续执行后面的操作;如果用户这时候离开了计算机,或者没有对这些对话框进行确定操作的话,可想而知,整个系统因为这个事务没有结束而通通处于等待状态了。