如何正确地从 Class 引发错误

How to Properly Raise Errors From Class

我的问题是:如何在 class 中正确引发错误,以便实例化 class 的调用者可以使用正确的错误处理技术?

我正在升级未使用 classes 的旧 VB6 意大利面条代码。过去我总是使用 On Error Resume NextOn Error Goto myLabel 用于在备选方案对我的代码没有任何清洁效果时处理错误。

但是,我无法让调用者处理错误,因为如果我在方法或 class 的 属性 中引发错误,无论我是否使用 On Error 语句从调用者那里捕获它。示例代码如下所示:

我的班级:

Public Sub Bar()
    If valid Then
        'some code here
    Else
        Err.Raise 5
    End if
End Sub

主窗体:

Private Sub CallFoo()
    Dim foo as New MyClass

    On Error Goto fooliure 'Starts ignoring errors
    Call foo.Bar() 'Program stops with an exception
    On Error Goto 0 'Ends error handling

    Exit Sub
    fooliure:
        'Error handling code
End Sub

Microsoft 还表示,这就是他们打算在 VB 6.0 中执行错误处理的方式,如前所述 here

此时我正在考虑在我的 class 中使用一个对象来收集调用者可以检索的错误。如果我能避免那样做,我会的,但到目前为止我还没有找到答案。

David,这是关于 VBA 错误处理 101 的简短教程。

  • Err 对象。这是一个保存当前错误的单例对象。不要尝试实例化此对象(即不要使用 Set objErr = New Err——这会失败)
  • On Error - 设置错误处理。可能的错误处理程序:
    • On Error GoTo Label - 遇到错误时执行跳转到Label
    • On Error Resume Next - 执行遇到错误时跳转到下一行
    • On Error GoTo 0 - 关闭当前错误处理程序。任何后续错误将由调用者处理
    • On Error Resume - 执行跳转到导致错误的行(不推荐)
  • Err 对象在以下情况下被清除(丢失当前错误):
    • 子程序、函数或属性被调用
    • 子程序、函数或属性正常退出
    • 一个On Error语句被执行
    • Err.Clear调用时清除当前错误
  • 引发异常。您可以在需要时随时提出错误。规范形式:

    Err.Raise 1001 + vbObjectError, Description:="An exception occurred."
    
  • 自定义错误:使用vbObjectError来生成用户定义的错误。例子:
    • 1001 + vbObjectError
    • 整数范围是0到65535
  • 错误处理顺序:
    1. 如果例程中定义了本地错误处理程序,则执行它
    2. 如果没有本地处理程序,则向调用者抛出错误
    3. 如果调用者没有处理程序,则不断引发错误,直到找到本地处理程序
    4. 如果没有顶级处理程序,应用程序终止
  • 创建错误链。创建显示原始错误的错误链并在错误发生时显示堆栈上的例程列表非常有用。去做这个:
    • 每个 可能导致错误的例程添加错误处理
    • 始终向调用者重新提出错误
    • 在重新引发错误时将字符串添加到 Err.Source 命名例程
    • 顶层调用例程可以使用MsgBox来通知用户错误(或者可以实现其他日志记录)

下面是演示这些想法的代码示例:

Public Sub TestErrorLevel1()

    On Error GoTo HandleErr ' clears Err object

    TestErrorLevel2

    Exit Sub

HandleErr:
    ' top-level error handler -- nothing else to raise error to
    ' show error and complete call chain
    MsgBox "Error: " & Err.Number & vbCrLf & Err.Description & vbCrLf _
        & "Source: modTest.TestErrorLevel1" & vbCrLf & Err.Source
End Sub

Public Sub TestErrorLevel2()

    On Error GoTo HandleErr ' clears Err object

    TestErrorLevel3

    Exit Sub

HandleErr:
    ' re-raise error, adding this subroutine to call chain
    Err.Raise Err.Number, "modTest.TestErrorLevel2" & vbCrLf & Err.Source, Err.Description
End Sub

Public Sub TestErrorLevel3()

    On Error GoTo HandleErr ' clears Err object

    Err.Raise 1001 + vbObjectError, Description:="User-defined error. Offset range from 0 to 65535"

    Exit Sub

HandleErr:
    ' re-raise: add module and routine to originating error
    Err.Raise Err.Number, "modTest.TestErrorLevel3" & vbCrLf & Err.Source, Err.Description
End Sub