设为首页 加入收藏

TOP

Delphi高手突破(三) Delphi高级进阶(一)
2017-10-10 12:05:08 】 浏览:2032
Tags:Delphi 高手 突破 高级 进阶

第 3章  异常及错误处理

健壮的程序来自于正确的错误处理。
 
 
 
 
相信我,总会有意外的……

Delphi  高手突破     
正如同现实生活中我们不可能事事如意,你所写的代码也不可能每一行都能得到正确
的执行。生活中遇到不如意的事情,处理好了,雨过天晴;处理不好,情况会越变越糟,
甚至一发而不可收拾,后果难料。程序设计中同样如此,所谓健壮的程序,并非不出错的
程序,而是在出错的情况下能很好地处理的程序。
因此,错误处理一直是程序设计领域的一个重要课题。而异常就是面向对象编程提供
的错误处理解决方案。它是一个非常好的工具,如果你选择了 OOP,选择了 Delphi,那么
异常也就成为你的惟一选择了。
要让你信服地选择异常,需要给出一些理由。在本章中会让你清楚明白地了解异常所
带来的好处。
3.1  异常的本质
什么是异常?为什么要用它?
在基于函数的结构中,一般使用函数返回值来标明函数是否成功执行,并给出错误类
型等信息。于是就会产生如下形式的代码:
 
nRetVal := SomeFunctionToOpenFile();
 
if nRetVal = E_SUCCESSED then // 成功打开
begin
  ……
end
else if nRetVal = E_FILE_NOT_FOUND then // 没有找到文件
begin
  ……
end
else if nRetVal = E_FILE_FORMAT_ERR then // 文件格式错
begin
  ……
end
else then
begin
  ……
end
 
使用返回错误代码的方法是非常普遍的,但是使用这样的方法存在两个问题:
(1)造成冗长、繁杂的分支结构(大量的 if 或 case 语句),使得程序流程控制变得
复杂,同时造成测试工作的复杂,因为测试需要走遍每个分支。
 
·50·

异常及错误处理
(2)可能会存在没有被处理的错误(函数调用者如果不判断返回值的话)。
异常可以很好地解决以上两个问题。
所谓“异常”是指一个异常类的对象。Delphi 的 VCL 中,所有异常类都派生于 Exception
类。该类声明了异常的一般行为、性质。最重要的是,它有一个 Message 属性可以报告异
常发生的原因。
抛出一个异常即标志一个错误的发生。使用 raise 保留字来抛出一个异常对象,如:
3
raise Exception.Create(′An error occurred!′);
但需要强调的是,异常用来标志错误发生,却并不因为错误发生而产生异常。产生异
常仅仅是因为遇到了 raise,在任何时候,即使没有错误发生,raise 都将会导致异常的发生。 注意:异常的发生,仅仅是因为 raise,而非其他!
一旦抛出异常,函数的代码就从异常抛出处立刻返回,从而保护其下面的敏感代码不
会得到执行。对于抛出异常的函数本身来说,通过异常从函数返回和正常从函数返回(执
行到函数末尾或遇到了 Exit)是没有什么区别的,函数代码同样会从堆栈弹出,局部简单
对象(数组、记录等)会自动被清理、回收。
采用抛出异常以处理意外情况,则可以保证程序主流程中的所有代码可用,而不必加
入繁杂的判断语句。
例如,函数 A抛出异常:
 
function A() : Integer;
vat
  pFile : textfile;
begin
  …… // 一些代码
  pFile := SomeFunctionToOpenAnFile();
  if pFile = nil then
raise Exception.Create(′Open file failed!′); // 文件打开失败抛出异常
 Read(pFile, ……); // 读文件
  …… // 其他一些对文件的操作,此时可以保证文件指针有效
end;
 
函数 A的代码使得对文件打开的出错处理非常简单。如果打开文件失败,则抛出一个
Exception 类的异常对象,函数立刻返回,从而保护了以下对文件指针的操作不被执行。而
之后的代码可以假设文件指针肯定有效,从而令代码更加美观。
生活中,我们每天扔掉的垃圾都会有清洁工人收拾、处理,否则生活环境中岂不到处
充斥着垃圾?同样,抛出的异常也需要被捕获和处理。假设函数 B 调用了函数 A,要捕获
这个文件打开失败的异常,就需要在调用 A 之前先预设一个陷阱,这个陷阱就是所谓的
“try…except 块”。
 
·51·

Delphi  高手突破     
先看一下函数 B 的代码:
 
procedure B();
begin
  …… // 一些代码
 try
   A(); // 调用A
   SomeFunctionDependOnA(); // 依赖于A的结果的函数
 Except
   ShowMessage(′some error occured′); // 嘿嘿,掉进来了,发生异常
 End;
  …… // 继续的代码
end;
 
A抛出的异常,会被 B所设的 try…except 所捕获。一旦捕获到异常,就不再执行之后
的敏感代码,而是立刻跳至 except 块执行错误处理,处理完成后再继续执行整个 try 块之
后的代码。程序流程的控制权被留在了函数 B。
如果不喜欢自己收拾垃圾,因而在 B 中并没有预设 try…except 块的话,则异常会被继
续抛给 B 的调用者,而如果 B 的调用者同样不负责任,则异常会被继续像踢足球一样被踢
给更上层的调用者,依此类推。不过,不用担心,我们有一个大管家,大家都不要的烫手
山芋,它会帮我们收拾,那就是——VCL(Delphi 的应用程序框架)。
因为 VCL 的框架使得所编写的整个应用程序被包在一个大的 try…except 中,无论什
么没有被处理的异常,最终都会被它所捕获,并将程序流程返回到最外层的消息循环中,
决无遗漏!这也就是为什么会看到很多用 Delphi 所编写的但并不专业的小软件有时会跳出
一个报告错误的对话框(如图 3.1 所示)。发生这样的情况应该责怪软件的编写者没有很
好地处理错误,但有些不明白异常机制的程序员常常会责怪 Delphi 编写的程序怎能会有这
样的情况发生。其实出现这个提示,应该感谢 VCL的异常机制让程序可以继续运行而不是
“非法终止”。
 
图3.1  异常被VCL所捕获 注意:VCL 用一个大的 try…except 将代码包裹起来!
因此,在 VCL 框架中不会有不被处理的异常,换句话说,也就是不会有不被处理的错
误(虽然笔者说过异常并不等于错误)。对异常的捕获也非常简单,不见了一大堆的 if 或
 
·52·

异常及错误处理
case,程序控制流程的走向也就十分清晰明了了,这是给测试人员带来的好消息。
3.

首页 上一页 1 2 3 4 下一页 尾页 1/4/4
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇[修正] Firemonkey TSelection 控.. 下一篇[修正] 移动平台曲线不平滑的问题..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目