VFP 8:新的错误处理机制

shanjuhua 2004-11-04 09:37:20
VFP 8:新的错误处理机制
--------------------------------------------------------------------------------
作者 Antonio Casta
译者 RMH


=================
介绍
=================
一种编程语言或软件开发工具的一个最重要的功能是能够提供正确处理错误的机制.

一个好的错误处理将使得开发时间缩短并简单化代码编写. 一个好的错误处理策略是区别高级的专业开发与业余爱好者的因素之一.

我个人认为, 在该新版本的 Visual FoxPro 中的一个最重要的改进是可以进行结构化错误处理.

除该机制自己提供的好处外, 它也把 Visual FoxPro 放入到 .NET 框架及其所有编程语言错误处理策略同步的地位.

该功能通过以下命令来实现:

TRY
CATCH
FINALLY


=================
在发生错误时做什么
=================
直到目前为止, Visual FoxPro 依赖于继承于 xBase(以及一些早期语言的) 经典的错误处理管理:

面对各种可以发生错误的场合, 该技术是, 在执行了一个给定的语句后, 分析 (或测试) 可能的操作结果. 这是转换成一个长的 IF...ELSE...ENDIF 指令串, 插入并散布在我们的代码中.

这种强烈的地使用 IF 语句会产生代码混淆, 难于阅读和维护. 而且这种情况使得应用程序的复杂性成指数级地增长.

要避免 IF 的繁殖, 并处理可能产生的不能预料的事件并中断程序的执行, 一种手段是在代码中包含一个 ON ERROR DO HandleError() 语句, 及其相应的 HandleError() 例程; 该例程将是一个可以检测错误类型并使程序在调后可以继续运行的过程.

随着 Visual FoxPro 3 的出现, 该错误处理可能达到 "对象级", 通过使用 Error 方法,允许封装一个错误处理管理器到一个特定的类中.

这些技术通常称为 "代码隔离": 可能产生错误的代码块被隔离开, 并且错误管理通常是 "本地地" 执行. 这允许通过代码减少和分散 IF 语句的数量.
这些错误处理技术在多数情况下是适当的, 但是一但我们进入到一个每样东西都是组件, 而且组件必须正确地面对它们可以使用的每一种场合的开发模式时, 该技术就不够了. 或者说至少, 它要求数量巨大的额外代码来达到相同的目标和结果.

在一个基于组件的软件开发场景中, 错误处理策略必须达到和具有一系列的目标和特性:

它必须允许一个适当的执行流控制: 意思是面对一个错误条件, 它必须允许我们适当地处理那些执行必须中断

和其它一些情形, 和不知原因的, 执行一个 "复盖" 操作的继续.

执行绝不停止, 其它组件可以因我们的影响而与我们交互.

它可以允许适当通讯关于与错误相关的种类和信息, 因此其它组件可以因为错误的发生而起反应.

关系到前面的问题, 它可以允许适当的传送错误信息. 意思是它应该提供一些机制来促进 "错误传递" 到执行链上. 许多时间错误发生在一个被另一个组件调用的组件中, 它自己被另一个调用, 等等. 有时候仅一可行的选择是报告希望的动作不能完成, 但是能够得到引起错误的组件的信息是重要的. 这将允许向用户提供有意义的信息, 而且同时, 也使错误的诊断和修正更为容易.
要达到所有这些目标, 使用新的异常处理实现起来是非常容易的.

我们只是公正地提及有比老式的方式更灵活的方法存在, 没有免除开发者适当地设计和实现体系, 包括所有的错误处理的相关材料. 而且这样也没有免除他的一般的编程责任. 也就是说, 对于成功的异常处理策略, 要求开发者总是按照前面定义的标准始终如一地使用它.


=================
结构化异常处理
=================
这种异常处理机制是按许多软件开发模式实现的, 如象 C++, Java, 而且从现在开始, 所有的 .Net 语言如 C# 和 VB.Net, 将使用更好的和更有效的错误管理方式. 基本的方法是:

  每次发生错误时, 一个异常被创建并 "抛出".
以处理存在的错误, 或 "监视" 该异常.

要实现这一点, 使用一个 TRY ... CATCH ... FINALLY 块. 可能产生错误的代码被 TRY 子句隔离, 并且当错误实际发生时, 执行控制转到 CATCH 子句. 可选的子句 FINALLY 无论错误是否出现都要执行.

完整的语法是:

TRY
[ tryCommands ]
[ CATCH [ TO VarName ] [ WHEN lExpression ]
[ catchCommands ]]
[ FINALLY
[ finallyCommands ]]
ENDTRY

一但程序运行到块的开始处 (TRY), 如果代码无错误地完成了, 流继续到代码中的 FINALLY 子句. 如果没有错误就不执行 CATCH 命令.

如果错误发生了, Visual FoxPro 分析块中的 CATCH 命令. 以一种类似于处理 DO CASE... 结构的方式, 每一个 lExpression 定义包含在 CATCH 命令的 WHEN 部分必须等值为一个逻辑值. 如果找到与产生的异常 (lExpression 是 .T.) 匹配的 CATCH 命令, 则相应组内的代码行被执行.

最后, 执行 FINALLY 子句中的代码. 意思是没有 CATCH 命令被求值. 即使没有需要处理的异常或 CATCH 段中没有求值为 .T. 的表达式, FINALLY 块也会被执行.

一个 EXIT 命令可以放到任何 CATCH 块或 FINALLY 块中.只要在 CATCH 块中找到 EXIT, 执行就从 FINALLY 块继续; 如果在 FINALLY 块中找到它, 则执行转到 ENTRY 语句后.

Si el error ocurre dentro de un m閠odo de un objeto que es llamado dentro de un bloque TRY, Visual FoxPro respeta el procedimiento de error de ese objeto (es decir, ejecuta su m閠odo Error). Esto permite mantener el principio de encapsulamiento de los componentes. Si no existe m閠odo Error, entonces la instrucci髇 CATCH correspondiente es ejecutada.

可能有一个没有任何条件的 CATCH 命令. 在这种情况下, 它相当于 CATCH WHEN .T. 这用在所有可能的条件在一个代码块中处理的场合.

到目前为止看来它与 DO CASE... 或一组 IF 没有太大的区别, 可能写得更好一些. 但这是真正有趣的东西的开始: 每一次在 TRY ... CATCH ... FINALLY 块中发生错误时, Visual FoxPro 从 Exception 类创建一个对象实例.

如果在 CATCH 语句中的任何表达式的值为 True (.T.), Visual FoxPro 对 <>TO VarName 子句中指定的变量赋值到一个真正的对象引用.

该变量的作用域取决于它先前是如何定义的. 如果它还没有被定义, 它被创建为么有变量.

让我们看看我们可以设想的简单的示例:

TRY
USE NonExistent

CATCH TO oExp
SUSPEND

FINALLY
* 未发生什么
ENDTRY

如果我们执行以上代码, 一但挂起程序, 我们可以从命令窗口中检查 Visual FoxPro 创建的 oExp 对象.

一个理解该机制的基本元素是理解和考虑 TRY ... CATCH ... FINALLY 结构可以嵌套. 事实上, 作为相互调用的组件, 这种情况经常发生的. 而且这自然是允许我们传递有意义的信息的方法.
...全文
39 1 打赏 收藏 举报
写回复
1 条回复
切换为时间正序
当前发帖距今超过3年,不再开放新的回复
发表回复
shanjuhua 2004-11-04
  • 打赏
  • 举报
回复
(续上帖)
=================
传递异常
=================
在一个 CATCH 块中, 可以用 THROW 命令再抛出 (re-throw) 一个异常. 这允许 "提升" 错误到执行链中的另一个错误处理器, 假如存在一个的话.

语法是:

THROW eUserExpression

以下是一个稍长的示例, 展示了块嵌套的用法:

LOCAL x AS Integer, y AS Integer, result AS Integer
LOCAL oErr AS Exception, oErr1 AS Exception
TRY
x = 1
TRY
USE Nothing
GO TOP
y = Nothing.col1
CATCH TO oErr
oErr.Uservalue = "嵌套的 CATCH 信息: 不能处理"
?[: 嵌套的 Catch! (未处理: 向上抛出 oErr 对象) ]
?[ 在 Exception 对象内: ]
?[ 错误: ] + STR(oErr.ErrorNo)
?[ 行号: ] + STR(oErr.LineNo)
?[ 信息: ] + oErr.Message
?[ 过程: ] + oErr.Procedure
?[ 细节: ] + oErr.Details
?[ 栈级: ] + STR(oErr.StackLevel)
?[ 行内容: ] + oErr.LineContents
?[ 用户值: ] + oErr.Uservalue
THROW oErr
FINALLY
?[: 嵌套的 FINALLY 被执行 ]
IF USED("nothing")
USE IN nothing
ENDIF
ENDTRY
result = x-y
CATCH TO oErr1
?[: 外部 CATCH! ]
?[ 外部 Exception 对象: ]
?[ 错误: ] + STR(oErr1.ErrorNo)
?[ 行号: ] + STR(oErr1.LineNo)
?[ 信息: ] + oErr1.Message
?[ 过程: ] + oErr1.Procedure
?[ 细节: ] + oErr1.Details
?[ 栈级: ] + STR(oErr1.StackLevel)
?[ 行内容: ] + oErr1.LineContents
?[ ->Uservalue 变为内部异常 THROWn 自嵌套的 TRY/CATCH ]
?[ 错误: ] + STR(oErr1.Uservalue.ErrorNo)
?[ 信息: ] + oErr1.Uservalue.Message
?[ 过程: ] + oErr1.Uservalue.Procedure
?[ 细节: ] + oErr1.Uservalue.Details
?[ 栈级: ] + STR(oErr1.Uservalue.StackLevel)
?[ 行内容: ] + oErr1.Uservalue.LineContents
?[ 用户值: ] + oErr1.Uservalue.Uservalue
result = 0
FINALLY
?[: FINALLY 语句被执行 ]
ENDTRY
RETURN result

在该示例中, 当在 USE... 语句中发生异常时, Visual FoxPro 创建 oErr 对象 (CATCH TO oErr). 在 TRY ... CATCH ... FINALLY 块内部简单地执行一个由 Visual FoxPro 创建的 Exception 对象的 THROW. 当 THROW oErr 被执行后, Visual FoxPro 创建一个新的 Exception 对象. oErr1, 它是接收自一个更高层的错误处理器, 一个 Uservalue 属性包含了 oErr 对象.

这是最常见的使用 THROW 命令的方法: THROW 语句中的 eUserExpression 是一个引用 CATCH 的 TO 表达式中的 Exception 对象的内存变量.

但是有可能传递最初由 Visual FoxPro 创建的相同的 Exception 对象 (在这种情况下 eUserExpression 可以缺省), 也创建一个的 Exception 对象, 但有一点不同的东西是在第一个 Exception 对象的 Uservalue 属性中 (eUserExpression 可以是任何类型的表达式).

如果 THROW 执行发生在 TRY ... CATCH ... FINALLY 结构之外, 这意味着当一个 TRY ... CATCH ...

FINALLY 不是在另一个之中, Visual FoxPro 调用 ON ERROR 中的例程或 Error 方法向上发送异常, 如果它们中的某一个存在. 否则, 就调用系统的错误处理器.


=================
Exception 类
=================
Visual FoxPro 创建的 Exception 对象总是派生自 Exception 基类, 且不可能在创建对象时执行用户代码.

该技术用于一个错误由 THROW 命令引发时处理我们的子类 Exception 对象, 代替使用 Visual FoxPro-创建的对象, 我们可以引发一个自定义的派生对象.

因此, 当我们执行:

THROW eUserExpression

eUserExpression 将是一个包含了我们刚创建的, Exception 类的子类的实例的对象引用.

一小点警告: THROW 命令可以用在 TRY ... CATCH ... FINALLY 结构之外, 但这样做会让我们的程序以非正常方式终止.


=================
让我们工作!
=================
Visual FoxPro 中的已存在的结构化错误处理允许我们创建更坚固, 清晰和易维护的应用程序和组件.

但是, 千万不要忘记, 除其它开发技术外, 错误处理是你开始开发一个新项目时需要做的第一件事.

可以使用 TRY ... CATCH ... FINALLY 为我们提供一系列新选择, 但当我们在开发工作中使用它之前, 高度建议投入所有必要的时间来完全理解它是如何工作的, 异常是如何从一个级传递到另一个级的, 以及该机制如何与其它我们已经创建的组件相结合.


(完)
发帖
VFP

2573

社区成员

VFP,是Microsoft公司推出的数据库开发软件,用它来开发数据库,既简单又方便。
社区管理员
  • VFP社区
加入社区
帖子事件
创建了帖子
2004-11-04 09:37
社区公告
暂无公告