说到错误和异常处理,高级开发语言一般会提供断言,try-catch或返回值机制。坦率地说,VBScript提供的异常处理机制,甚至比它同家族的其他成员都要来得弱。这可能会阻止一些“真正的”程序员使用VBScript开发语言,毕竟,不能对错误和异常有足够的控制力,是一件很让人不安的事。但是考虑到VBScript应该应用的场合和面向的对象,我们不应该诘难VBScript语言的设计者。VBScript脚本绝大多时候用于执行有人值守,轻量级的系统管理任务,而且要宜于编写和快速完成–不可能让编写脚本的花的时间比人工执行这些管理任务还要费时!当然,VBScript语言正在获得更加广泛的应用,有些应用还十分关键,比如,QuickTestPro已经选用它作为测试脚本语言。如果你也用VBScript来完成一些关键应用,比如super lab测试,建议认真阅读本节,以真正了解VBScript在应付异常方面和错误恢复的能力。
关于VBScript的异常处理机制,似乎两个声明语句和一个变量就是全部,它们是Err对象和:
on error resume next
on error goto 0
声明语句。
从语义上看,On error resume next似乎直观一些,它好象是在说没有错误处理,直接换下一句执行。而On error goto 0是什么意思?需要在程序中添加一个标号为0的错误处理例程吗?
Basic语言的早期使用者应该对行号不陌生。正确的行号从1开始,0是非法行号。因此On error goto 0在这里并不意味着跳转,反而意味着关闭错误处理。
On error resume next和On error goto 0声明了一个错误处理的作用域。在这个作用域里发生的错误会被脚本(程序员)捕获到。而不在任何上述作用域以外的地方发生的异常,会引起脚本执行终止。记住错误处理作用域支持嵌套,下面的两个例子都是有效的,当然第二个看上去略为有意义一些:
例1:
Sub Blah2()
WScript.Echo "Blah2 Start"
Err.Raise InvalidCall
WScript.Echo "Blah2 End"
End SubOn Error Resume Next
WScript.Echo "line 1"
Blah2
On Error Resume Next
WScript.Echo "line 4"
Blah2
On Error GoTo 0
WScript.Echo "line 7"
On Error GoTo 0
WScript.Echo "line 9"
例2:
Sub Blah2()
WScript.Echo "Blah2 Start"
Err.Raise InvalidCall
WScript.Echo "Blah2 End"
End Sub
Sub foo()
On Error Resume Next
Blah2
On Error GoTo 0
End SubOn Error Resume next
WScript.Echo "start"
foo
WScript.Echo "end"
On Error GoTo 0
在例2中我对On Error对(pair)中间的语句进行了缩进。这正是我想表达的意思,简练地说,可以把这个对(pair)看成一个合并的Try–Catch,错误捕获和处理在一起完成,或者说错误处理必须是内联的,不允许跳到别的什么行号或标记处去执行,这在其他基于basic的语言中是允许的。正如Try–Catch的辗转解开一样,On Error pair也有类似的属性。在例2中,如果foo()过程定义如下:
Sub foo()
WScript.Echo "foo start"
Blah2
WScript.Echo "foo end"
End Sub
则过程Blah2中发生的抛出的异常,会导致WSCript.Echo "foo end"无法被执行,而直接跳到WSCript.Echo "end"一句,因为只有在这里才找到一个"Try"声明(On Error Resume Next),堆栈的辗转开解才结束。按照On Error Resume Next的语义,应该从当前调用栈的下一语句执行,即WSCript.Echo "end"。
在过程Blah2中,我使用了Err对象,现在是时候谈谈这个对象了。首先,在任何时候,任何地方都可以使用这个对象。Err对象有三个属性,缺省属性number,description和source。
Number是缺省属性,所以这样的比较if (6 = Err)是允许的。VBScript允许的错误码在1 - 65535范围内(VBScript+用户)。我不是很清楚用户自定义错误码可以使用的范围,但帮助文档说,在自动化对象中使用自定义错误码,应该从vbObjectError + 1处开始。Source代表着应用程序标识或者一个类对象说明(COM),也可以在自定义异常中,直接添加脚本文件名和行号进来,以方便调试。遗撼的是,并没有__FILE__和__LINE__这样的宏可以使用,因此添加文件名和行号是件很费时的事。
Err对象的初始化值是number = 0,description = ""。当On Error Resume Next和On Error Goto 0以及方法Clear被调用时,Err被初始化。Raise方法比较直观,它的原型是:
object.Raise(number, source, description, helpfile, helpcontext)
最后,提供一个错误处理函数。这个错误处理函数其实不做处理,它只是输出错误信息并退出脚本执行。
sub DumpErrAndQuit(strObj, strErrReportMethod)
dim errnum
errnum = Err.Numberwscript.Echo "Error 0x" & CStr(Hex(errnum)) & " occurred."
if len(Err.Description) Then
wscript.Echo "Error Description: " & Err.Description
end If
if len(Err.Source) then
wscript.Echo "Error Source : " & Err.Source
end If
if len(strObj) Then
wscript.Echo "Special Description: "
Dim CmdStr
CmdStr = "wscript.Echo " & strObj & "." & strErrReportMethod
Execute CmdStr
End If
wscript.quit(0)
end Sub