📄 029.htm
字号:
<HTML><HEAD><meta http-equiv="Content-Type" content="text/html; charset=GB2312"><TITLE>-->DELPHI基础教程-->第十二章 异常处理与程序调试(二)</TITLE>
<META NAME="keywords" CONTENT=" DELPHI基础教程 第十二章 异常处理与程序调试(二)">
<META NAME="description" CONTENT=" - DELPHI基础教程 - 第十二章 异常处理与程序调试(二)">
<style>
<!--
#page {position:absolute; z-index:0; left:0px; top:0px}
.tt3 {font: 9pt/12pt "宋体"}
.tt2 {font: 12pt/15pt "宋体"}
a {text-decoration:none}
a:hover {color: blue;text-decoration:underline}
-->
</style>
</HEAD>
<body text="#000000" aLink=#9900ff link=#006699 vLink=#006699 background="bg.gif" leftmargin="3" topmargin="3" marginheight="3" marginwidth="3">
<TR>
<TD CLASS="tt3" VALIGN="top" width="8%" background="bg.gif"><strong><A HREF="030.htm" ><FONT style="FONT-SIZE: 9pt">后一页</font></A><BR>
<A HREF="028.htm" ><FONT style="FONT-SIZE: 9pt">前一页</font></A><BR>
<A HREF="index.html" ><FONT style="FONT-SIZE: 9pt">回目录</font></A><BR>
<A HREF="../../../../../index.htm"><FONT style="FONT-SIZE: 9pt">回首页</font></A><BR>
</strong>
</TD>
<TD class="tt2" background="bg.gif" width="84%"><center><B><FONT style="FONT-SIZE: 16.5pt" COLOR="#FF6666" FACE="楷体_GB2312">第十二章 异常处理与程序调试(二)</FONT></B></center>
<hr color="#EE9B73" size="1" width="94%">
</font><p align="center">12.3<font face="宋体" lang="ZH-CN"> 异常响应 </p>
<p> </font> <font face="宋体" lang="ZH-CN">异常响应为开发者提供了一个按自己的需要进行异常处理的机制。</font>try
<font face="宋体" lang="ZH-CN">…</font>except <font face="宋体" lang="ZH-CN">…</font>end<font
face="宋体" lang="ZH-CN">形成了一个异常响应保护块。与</font>finally<font
face="宋体" lang="ZH-CN">不同的是:正常情况下</font>except <font face="宋体"
lang="ZH-CN">后面的语句并不被执行,而当异常发生时程序自动跳到</font>except<font
face="宋体" lang="ZH-CN">,进入异常响应处理模块。当异常被响应后异常类自动清除。</p>
<p> 下面的例子表示了文件打开、删除过程中发生异常时的处理情况: </p>
</font><p>uses Dialogs;</p>
<p>var</p>
<p>F: Textfile;</p>
<p>begin</p>
<p>OpenDialog1.Title := 'Delete File';</p>
<p>if OpenDialog1.Execute then</p>
<p>begin</p>
<p>AssignFile(F, OpenDialog1.FileName);</p>
<p>try</p>
<p>Reset(F);</p>
<p>if MessageDlg('Erase ' +OpenDialog1.FileName + '?',</p>
<p>mtConfirmation, [mbYes, mbNo], 0) = mrYes then</p>
<p>begin</p>
<p>System.CloseFile(F);</p>
<p>Erase(F);</p>
<p>end;</p>
<p>except</p>
<p>on EInOutError do</p>
<p>MessageDlg('File I/O error.', mtError, [mbOk], 0);</p>
<p>on EAccessDenied do</p>
<p>MessageDlg('File access denied.', mtError, [mbOk], 0);</p>
<p>end;</p>
<p>end;</p>
<p>end.</p>
<font face="宋体" lang="ZH-CN"><p> 保留字</font>on<font face="宋体"
lang="ZH-CN">…</font>do<font face="宋体" lang="ZH-CN">用于判断异常类型。必须注意的是:</font>except<font
face="宋体" lang="ZH-CN">后面的语句必须包含在某一个</font>on<font
face="宋体" lang="ZH-CN">…</font>do<font face="宋体" lang="ZH-CN">模块中,而不能单独存在。这又是同</font>finally<font
face="宋体" lang="ZH-CN">不同的一个地方。 </p>
</font><p>12.3.1 <font face="宋体" lang="ZH-CN">使用异常实例 </p>
<p> 上面所使用的异常响应方法可总结为如下的形式: </p>
<p> </font>on ExceptionType do</p>
<p>{<font face="宋体" lang="ZH-CN">响应某一类的异常} </p>
<p> 这种方法唯一使用的信息是异常的类型。一般情况下这已能满足我们的需要。但我们却无法获取异常实例中包含的信息,比如异常消息、错误代码等。假设我们需要对它们进行处理,那么就必须使用异常实例。</p>
<p> 为了使用异常实例,需要为特定响应模块提供一个临时变量来保存它: </p>
<p> </font>on EInstance : ExceptionType do<font face="宋体" lang="ZH-CN"> … </font></p>
<font face="宋体" lang="ZH-CN"><p> 在当前响应模块中我们可以象使用一个普通对象那样来引用它的数据成员。但在当前响应模块之外不被承认。</p>
<p> 下面的代码用于获取异常消息并按自己的方式显示它: </p>
<p>{窗口中包括一个</font>ScrollBar<font face="宋体" lang="ZH-CN">部件,一个</font>Button<font
face="宋体" lang="ZH-CN">部件} </p>
</font><p>procedure TErrorForm.Button1Click(Sender: TObject);</p>
<p>begin</p>
<p>try</p>
<p>ScrollBar1.Max := ScrollBar1.Min-1;</p>
<p>except</p>
<p>on E: EInvalidOperation do</p>
<p>MessageDlg('Ignoring Exception:'+E.Message,</p>
<p>mtInformation,[mbOK],0);</p>
<p>end;</p>
<p>end; </p>
<p>12.3.2 <font face="宋体" lang="ZH-CN">提供缺省响应 </p>
<p> 在异常响应模块中,一般我们只对希望响应的特定异常进行处理。如果一个异常发生而响应模块并没有包含对它的处理代码,则退出当前响应模块,异常类仍被保留。</p>
<p> 为了保证任何异常发生后都能在当前响应模块中被清除,可以定义缺省响应: </p>
</font><p>try</p>
<p>{<font face="宋体" lang="ZH-CN">程序正常功能}</font></p>
<p>except</p>
<p>on ESomething do</p>
<p>{<font face="宋体" lang="ZH-CN">响应特定异常}</font></p>
<p>else</p>
<p>{<font face="宋体" lang="ZH-CN">提供缺省响应}</font></p>
<p>end; </p>
<p><font face="宋体" lang="ZH-CN">由于</font>else<font face="宋体" lang="ZH-CN">可以响应任何异常,包括我们一无所知的异常,因此在缺省响应中最好只包括诸如显示一个消息框之类的处理,而不要改变程序的运行状态或数据。 </p>
</font><p>12.3.3 <font face="宋体" lang="ZH-CN">响应一族异常 </p>
<p> 诸如</p>
</font><p><font face="宋体" lang="ZH-CN"> on ExceptionType do</font></p>
<font face="宋体" lang="ZH-CN"><p>的异常响应语句不仅可响应本类异常,而且可以响应子类异常。对于象</font>EIntError<font
face="宋体" lang="ZH-CN">、</font>EMathError<font face="宋体" lang="ZH-CN">等系统不会引发的异常,它们将只响应其子类异常。而对于象</p>
<p> </font>on Exception do</p>
<font face="宋体" lang="ZH-CN"><p>这样的语句将会对任何异常进行响应。</p>
<p> 下面一段代码对整数越界异常进行单独处理,而对其它整数异常进行统一处理: </p>
<p> </font>try</p>
<p>{<font face="宋体" lang="ZH-CN">整数运算}</font></p>
<p>except</p>
<p>on ERangeError do</p>
<p>{<font face="宋体" lang="ZH-CN">越界处理}</font></p>
<p>on EIntError do</p>
<p>{<font face="宋体" lang="ZH-CN">其它整数异常处理}</font></p>
<p>end;<font face="宋体" lang="ZH-CN"> </font></p>
<p><font face="宋体" lang="ZH-CN">由于异常在处理后即被清除,因而上面的代码可保证不会使</font>ERangeError<font
face="宋体" lang="ZH-CN">异常被多次处理。假如颠倒两条响应语句的顺序,则</font>ERangeError<font
face="宋体" lang="ZH-CN">异常响应将永远没有被执行的机会。 </p>
<p> 由于异常在处理后即被清除,因而当希望对异常进行多次处理时就需要使用保留字</font>raise<font
face="宋体" lang="ZH-CN">来重引发一个当前异常。</p>
<p> 下面的代码同时使用了异常响应和异常保护。异常响应用于设置变量的值,异常保护用于释放资源。当异常响应结束时利用</font>raise<font
face="宋体" lang="ZH-CN">重引发一个当前异常。 </p>
</font><p>var</p>
<p>APointer: Pointer ;</p>
<p>AInt , ADiv: Integer;</p>
<p>begin</p>
<p>ADiv := 0;</p>
<p>GetMem ( APointer , 1024 );</p>
<p>try</p>
<p>try</p>
<p>AInt := 10 div ADiv ;</p>
<p>except</p>
<p>on EDivByZero do</p>
<p>begin</p>
<p>AInt := 0 ;</p>
<p>raise;</p>
<p>end;</p>
<p>end; </p>
<p>finally</p>
<p>FreeMem ( APointer , 1024 );</p>
<p>end;</p>
<p>end;</p>
<font face="宋体" lang="ZH-CN"><p> 上面一段代码体现了异常处理的嵌套。异常保护、异常响应可以单独嵌套也可以如上例所示的那样相互嵌套。 </p>
</font><p>12.3.5 <font face="宋体" lang="ZH-CN">自定义异常类的应用 </p>
<p> 利用</font>Delphi<font face="宋体" lang="ZH-CN">的异常类机制我们可以定义自己的异常类来处理程序执行中的异常情况。同标准异常不同的是:这种异常情况并不是相对于系统的正常运行,而是应用程序的预设定状态。比如输入一个非法的口令、输入数据值超出设定范围、计算结果偏离预计值等等。</p>
<p> 使用自定义异常需要:</p>
<p> </font>1.<font face="宋体" lang="ZH-CN">自己定义一个异常对象类;</p>
<p> </font>2.<font face="宋体" lang="ZH-CN">自己引发一个异常。 </p>
</font><p>12.3.5.1 <font face="宋体" lang="ZH-CN">定义异常对象类 </p>
<p> 异常是对象,所以定义一类新的异常同定义一个新的对象类型并无太大区别。由于缺省异常处理只处理从</font>Exception<font
face="宋体" lang="ZH-CN">或</font>Exception<font face="宋体" lang="ZH-CN">子类继承的对象,因而自定义异常类应该作为</font>Exception<font
face="宋体" lang="ZH-CN">或其它标准异常类的子类。这样,假如在一个模块中引发了一个新定义的异常,而这个模块并没有包含对应的异常响应,则缺省异常处理机制将响应该异常,显示一个包含异常类名称和错误信息的消息框。</p>
<p> 下面是一个异常类的定义: </p>
<p> </font>type</p>
<p>EMyException = Class(Exception) ;<font face="宋体" lang="ZH-CN"> </font></p>
<p>12.3.5.2 <font face="宋体" lang="ZH-CN">自引发异常 </p>
<p> 引发一个异常,调用保留字</font>raise<font face="宋体" lang="ZH-CN">,后边跟一个异常类的实例。</p>
<p> 假如定义: </p>
</font><p>type</p>
<p>EPasswordInvalid = Class(Exception); </p>
<p><font face="宋体" lang="ZH-CN">则在程序中如下的语句将引发一个</font>EPasswordInvalid<font
face="宋体" lang="ZH-CN">异常: </p>
</font><p><font face="宋体" lang="ZH-CN"> </font>If Password <> CorrectPassword
then</p>
<p>raise EPasswordInvalid.Create('Incorrect Password entered');</p>
<font face="宋体" lang="ZH-CN"><p> 异常产生时把</font>System<font
face="宋体" lang="ZH-CN">库单元中定义的变量</font>ErrorAddr<font face="宋体"
lang="ZH-CN">的值置为应用程序产生异常处的地址。在你的异常处理过程中可以引用</font>ErrorAddr<font
face="宋体" lang="ZH-CN">的值。</p>
<p> 在自己引发一个异常时,同样可以为</font>ErrorAddr<font
face="宋体" lang="ZH-CN">分配一个值。</p>
<p> 为异常分配一个错误地址需要使用保留字</font>at<font
face="宋体" lang="ZH-CN">,使用格式如下: </p>
<p> </font>raise EInstance at Address_Expession; </p>
<p>12.3.5.3 <font face="宋体" lang="ZH-CN">自定义异常的应用举例 </p>
<p>下面我们给出一个利用自定义异常编程的完整实例。</font></p>
<p><font face="宋体" lang="ZH-CN">两个标签框</font>(Label1<font face="宋体"
lang="ZH-CN">、</font>Label2)<font face="宋体" lang="ZH-CN">标示对应编辑框的功能。编辑框</font>PassWord<font
face="宋体" lang="ZH-CN">和</font>InputEdit<font face="宋体" lang="ZH-CN">用于输入口令和数字。程序启动时</font>Label2<font
face="宋体" lang="ZH-CN">、</font>InputEdit<font face="宋体" lang="ZH-CN">不可见。当在</font>PassWord<font
face="宋体" lang="ZH-CN">中输入正确的口令时,</font>Label2<font face="宋体"
lang="ZH-CN">、</font>InputBox<font face="宋体" lang="ZH-CN">出现在屏幕上。此时</font>Label1<font
face="宋体" lang="ZH-CN">、</font>PassWord<font face="宋体" lang="ZH-CN">隐藏。</font></p>
<p><font face="宋体" lang="ZH-CN">设计时,令</font>Label2<font face="宋体"
lang="ZH-CN">、</font>InputEdit<font face="宋体" lang="ZH-CN">的</font>Visible<font
face="宋体" lang="ZH-CN">属性为</font>False<font face="宋体" lang="ZH-CN">。通过设置</font>PassWord<font
face="宋体" lang="ZH-CN">的</font>PassWordChar<font face="宋体" lang="ZH-CN">可以确定输入口令时回显在屏幕上的字符。</font></p>
<p><font face="宋体" lang="ZH-CN">自定义异常</font>EInvalidPassWord<font
face="宋体" lang="ZH-CN">和</font>EInvalidInput<font face="宋体" lang="ZH-CN">分别用于表示输入的口令非法和数字非法。它们都是自定义异常</font>EInValidation<font
face="宋体" lang="ZH-CN">的子类。而</font>EInValidation<font face="宋体"
lang="ZH-CN">直接从</font>Exception<font face="宋体" lang="ZH-CN">异常类派生。</font></p>
<p><font face="宋体" lang="ZH-CN">下面是三个异常类的定义。 </p>
</font><p>type</p>
<p>EInValidation = class(Exception)</p>
<p>public</p>
<p>ErrorCode: Integer;</p>
<p>constructor Create(Const Msg: String;ErrorNum: Integer);</p>
<p>end;</p>
<p>EInvalidPassWord = class(EInValidation)</p>
<p>public</p>
<p>constructor Create;</p>
<p>end;</p>
<p>EInvalidInput = class(EInValidation)</p>
<p>public</p>
<p>constructor Create(ErrorNum: Integer);</p>
<p>end; </p>
<p>EInValidation<font face="宋体" lang="ZH-CN">增加了一个公有成员</font>ErrorCode<font
face="宋体" lang="ZH-CN">来保存错误代码。错误代码的增加提供了很大的编程灵活性。对于异常类,可以根据错误代码提供不同的错误信息;对于使用者可以通过截取错误代码,在</font>try...except<font
face="宋体" lang="ZH-CN">模块之外来处理异常。</font></p>
<p><font face="宋体" lang="ZH-CN">从以上定义可以发现:</font>EInvalidPassWord<font
face="宋体" lang="ZH-CN">和</font>EInvalidInput<font face="宋体" lang="ZH-CN">的构造函数参数表中没有表示错误信息的参数。事实上,它们保存在构造函数内部。下面是三个自定义异常类构造函数的实现代码。 </p>
</font><p>constructor EInValidation.Create(Const Msg: String; ErrorNum: Integer);</p>
<p>begin</p>
<p>inherited Create(Msg);</p>
<p>ErrorCode := ErrorNum;</p>
<p>end;</p>
<p>constructor EInValidPassWord.Create;</p>
<p>begin</p>
<p>inherited Create('Invalid Password Entered',0);</p>
<p>end;</p>
<p>constructor EInValidInput.Create(ErrorNum: Integer);</p>
<p>var</p>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -