明经通道 发表于 2012-10-10 18:47:23

第四章 在 Visual LISP 中调试代码(四) Visual LISP错误捕获函数

Visual LISP错误捕获函数
Visual LISP在古老的AutoLISP *error*函数基础上,提供了一些额外的错误捕获和错误处理函数。这些函数的每一个都提供了一整套用于在Visual LISP代码执行中捕捉、判定和处理错误的工具集,尤其是对在自己的变量空间运行的代码或外部应用程序对象或程序连接的代码。例如,除非你使用了这些函数,否则有时对象ADO错误产生的错误,你很难去拦截或作出回应。

(vl-catch-all-apply ‘function list)
放置一个错误捕获在函数执行的结果上。它和C++、C#和VB.NET程序语言中提供的Try-Catch异常处理的行为相类似。返回成功的对象或一个出错对象。用(vl¬catch-all-error-p)函数来判断返回的对象是否是个错误对象。

参数:
Function :一个defun或lambda函数定义或者是符号指针
List :函数求值所需的参数列表

(vl-catch-all-apply)函数是用于在一组代码表达式周围放置一个错误捕获。一旦执行,所有的结果都会被传递到这个函数,这样就可以让它检查是否产生了错误。如果产生了错误,就检查其所产生错误的类型。

这个函数的语法是(vl-catch-all-apply function list),其中function指的是正在被执行的语句,list指的是在函数上被执行的项,或函数执行的方式。

提示!需要了解每一个你准备使用或连接的ActiveX对象。你必须小心确定当对象失败时它是否会“扔”出一个ActiveX或OLE错误。如果结果失败时,它能够“扔”出这样的一个错误(而不是返回nil),你就应该立即围绕这个语句,将其连接至内部的错误处理程序,而不是让你的代码激怒你的用户。

例如,在尝试打开Microsoft Excel时设置一个错误捕获,你可以象如下这样操作...

(cond ((vl-catch-all-error-p
         (setq XL (vl-catch-all-apply
                  'vlax-create-object
                  '("Excel.Application")
                  )
         )
       )
       (vl-exit-with-error
         (strcat "\n出错: " (vl-catch-all-error-message XL))
       )
      )
      (T (princ "\n成功打开Microsoft Excel进程对象。"))
)

这个小例子做了如下的工作(从里到外按照处理的顺序)
● 尝试创建Excel.Application对象
● 如果尝试失败则将XL变量做为错误对象返回。
● 用(vl-catch-all-error-p)来检验变量XL并返回T。
● 如果赋值失败,(vl-exit-with-error)函数显示从错误对象XL传递过来的错误信息。
● 这个错误导致代码立即终止执行并同时向用户显示信息。否则,如果(vl-catch-all-error-p)返回nil,则返回的XL对象不是错误对象,那么程序可继续处理更多的事情。

一个更简单的而直观的测试是强制执行“除以零”的程序来产生一个错误,然后看Visual LISP如何处理它。从LISP控制台的窗口内部,按顺序输入下面两行代码。第一行之后,你应该看到返回的错误对象是<%catch-all-apply-error%>。第二行之后,你应该看到,由错误对象返回的“除数为零”的字符串值信息。

_$ (setq catchit (vl-catch-all-apply '/ '(50 0)))
#<%catch-all-apply-error%>
_$ (vl-catch-all-error-message catchit)
"除数为零"

使用(vl-catch-all-apply)函数的一个好地方是当尝试用(vla-item)方法从集合中获取对象的时候。例如,你可能期望当没有匹配的对象时,以下代码块会返回零。然而,取而代之的是这些代码块会抛出一个ActiveX错误。

(setq layers
       (vla-get-layers
         (vla-get-activedocument (vlax-get-acad-object))
       )
)
(setq mylayer (vla-item layers "Doors"))

当一个命令失败时,做这件事的合适方法是应该用(vl-catch-all-apply)捕获错误,就象以下所示一样:

(if
(not
    (vl-catch-all-error-p
      (setq mylayer
             (vl-catch-all-apply 'vla-item (list layers "Doors"))
      )
    )
)
   (princ "\n在图层集合中找不到图层!")
   (princ "\n图层不存在。")
)

提示!这有一个例子,我在本书所有使用到(vla-item)的地方都会用到这个函数。它将返回一个对象,但如果在提供的集合中没有发现条目,那么它就返回nil。我高度推荐在使用(vla-item)的地方使用这样的一个函数以避免你的代码产生错误。

(defun get-item (collection item / result)
(if (not
      (vl-catch-all-error-p
          (setq
            result (vl-catch-all-apply 'vla-item (list collection item))
          )
      )
      )
    result
)
)

(vl-catch-all-error-p object)
返回T还是nil,取决于对象是否为一个错误对象。

参数:
Object – 任何vla-对象

示例:
(vl-catch-all-error-p (vl-catch-all-apply ‘/ ‘(50 0)))

这里将返回T(真),因为(/ 50 0)典型的“除数为零”错误。

(vl-catch-all-error-message object)
从一个错误对象中返回住处描述。如果Object不是一个错误对象,这个函数返回nil。

参数:
Object –任何vla-对象

示例:
(vl-catch-all-error-message (vl-catch-all-apply ‘/ ‘(50 0)))

这将显示一个 “除数为零”的错误信息。

(vl-exit-with-error message)
终止VLX执行并返回一个字符串信息结果。

参数:
Message – 一个包含出错信息结果的字符串

(vl-exit-with-error)函数可以立即终止执行并返回一个字符串数值作为结果。它帮助很大,可以传递一个自定义错误信息让用户更明确。除了你可以通过一个返回值做为错误的结果,这个函数很象AutoLISP中的(exit)函数,图4-8显示你如何通过(vl-catch-all-error-message)作为返回的信息值。

(vl-exit-with-value value)
终止VLX执行并返回一个数字或符号的结果值。

参数:
Value – 任何值或符号

示例:
(defun fubar (somevalue / *error*)
(defun *error* (s)
    (vl-exit-with-value s)
)
(/ somevalue 0)                     ; 强制除数为零错误
(defun errortest (/ try)
    (cond
      ((vl-catch-all-error-p
         (setq try (vl-catch-all-apply 'fubar (list 12)))
       )
       (princ (strcat "\n出错: " (vl-catch-all-error-message try)))
      )
    )
)
)

如果你加载了上面的例子并输入(errortest),结果就会是“出错:除数为零”。(vl-exit-with-value)函数除了它返回的结果是数值外,它和(vl-exit-with-error)函数的处理方法是一样的。如果你想用一个数值参数来处理错误,这个函数对你是有用的。例如传递一个ActiveX错误号的返回值。

如你从这些函数和示例中看到的,你可以执行非常具体的错误捕获并用Visual LISP来处理。它可以帮助你做出更高质量的代码和软件产品。不管怎么说这个练习并不是Visual LISP独有的。一般而言,这在其它如C/C++、Visual Basic、VBA、JAVA等的语言中也是一样的。错误捕获是个有意义的功能,但你要努力去有效地使用它,然后才能享受它带给你的好处。



http://bbs.mjtd.com/xwb/images/bgimg/icon_logo.png 该贴已经同步到 明经通道的微博

smartstar 发表于 2012-10-11 13:32:30

与明镜共同进步。

jdlfjk 发表于 2012-10-12 19:52:53

这个vl-catch-all-apply function list)函数不错,捕捉完了,可以忽略一些错误继续执行程序

zyhandw 发表于 2012-10-20 16:29:01

还需要加把劲啊,不太会用出错处理

pengfei2010 发表于 2014-1-1 12:55:38

不错不错 学习了

ltrliu 发表于 2015-8-11 10:41:02

一直没用过这个函数,菜鸟学习了

丶吟游诗人灬 发表于 2023-4-7 13:04:16

如果你加载了上面的例子并输入(errortest),结果就会是“出错:除数为零”。(vl-exit-with-value)函数除了它返回的结果是数值外,它和(vl-exit-with-error)函数的处理方法是一样的。如果你想用一个数值参数来处理错误,这个函数对你是有用的。例如传递一个ActiveX错误号的返回值。
这个例子看的有点懵,尝试并未达到预期效果 不知道哪里理解错了

wuzhenif 发表于 2023-8-27 18:40:47

有时候错误处理确实很有必要

13560288275 发表于 2023-12-16 08:56:28

学会了学会了
页: [1]
查看完整版本: 第四章 在 Visual LISP 中调试代码(四) Visual LISP错误捕获函数