错误时恢复旧VBA

问题描述 投票:1回答:3

假设你的主子中有On Error Defined。

Sub Main()

   On Error Goto CatchAll
   '... Some code... goes here
   Call XYZ



CatchAll:
   Msgbox "An Unexpected Error Occurred"
   End
End Sub

在Main子系统中,您可以调用常规XYZ。让我们说Sub XYZ是这样的:

Sub XYZ()
   'If unexpected error happens here, control will be shifted to sub Main, Label CatchAll

   On Error Goto Errorz

   'If unexpected error happens here, control will be shifted to same sub, Label Errorz...

Errorz:
        Msgbox "You have crashed inside XYZ"
        End

End Sub

请注意在子XYZ中输入的注释。也就是说,在经历程序崩溃之后控制转移的位置是基于最后的“On Error Goto”语句。

在VBA中,有没有办法恢复旧的On Error Goto?

换句话说,在Sub XYZ中,我有一些代码:

Sub XYZ()
   On Error Goto Errorz:

   'Some Code

   On Error Goto <Old Error Trapping Method>
   'Here I desire to go back to Main CatchAll: label.  Is there a way to do that?

End Sub

请注意上面代码中的最后一条评论。我希望能够在定义新行为之前重新定义On Error以恢复On错误的最后一个行为(Last Behavior:Goto Main.CatchAll label,New behavior,Goto XYZ.Errorz label)。我希望能够在代码的这一点上说,On Error Go to Main.CatchAll。

有没有办法实现这个目标?

vba onerror
3个回答
3
投票

是的,在XYZ()中

On Error Goto 0

应该清除当前过程的(即XYZ()的)错误处理程序,并在您的示例中将错误处理的控制传递给Main()中的错误处理程序。


0
投票

当然。没有直接的clearing local error handling,你可以有条件地重新抛出处理程序中的错误:

Errorz:
    With Err
        If .Number = SomeSpecificLocalError Then
            ' mitigate error
            Resume Next
        Else
            ' rethrow
            .Raise .Number
        End If
    End With

这样你就可以保留原始的错误信息(可选择你可以为“catch-all”处理程序指定一个source和一个更具描述性的message)和调用堆栈中的“冒泡”错误。

让我们来说明与另一种语言的区别:

try
{
    // do stuff
}
catch
{
    // handle error
}

// do more stuff

上面的片段基本上是On Error GoTo 0所做的:无论在do more stuff中发生什么,如果抛出错误,调用者将需要处理它。

现在比较:

try
{
    // do stuff
    // do more stuff
}
catch(InvalidOperationException e)
{
    // handle invalid operation
}
catch(FileNotFoundException)
{
    throw;
}
catch(Exception)
{
    // handle any other exception
}

这里局部范围将处理InvalidOperationException,但是将显式重新抛出FileNotFoundException以便调用代码来处理,而任何其他异常将在本地处理。

这两种方法都有优点和缺点,我只是将其留给后人:如果你愿意,可以在VBA中重新抛出运行时错误。

也就是说,在单个程序中需要多个错误处理策略是代码味道IMO:您的程序可能会导致太多事情,将其拆分。


0
投票

这很容易踢回到main并进入错误处理程序。

Option Explicit
Private Sub CommandButton1_Click()

On Error GoTo CatchAll

Call XYZ

Exit Sub

CatchAll:
MsgBox "This is Catchall Error Handling"
End Sub

Private Sub XYZ()

'This will purposely throw an error
'ThisWorkbook.Worksheets("Sheet55").Range("A1").Value = 10

On Error GoTo 0
'This will purposely throw an error
ThisWorkbook.Worksheets("Sheet66").Range("A1").Value = 10

MsgBox "You made it to here? Wow!"

End Sub

enter image description here

如果你必须有一个子错误处理程序,当使用rethrow时,下面的答案是正确的,也是有效的,你们这些人很聪明:

Option Explicit
Private Sub CommandButton1_Click()

On Error GoTo CatchAll

Call XYZ

Exit Sub

CatchAll:
MsgBox "This is Catchall Error Handling"
End Sub

Private Sub XYZ()

'This will purposely throw an error
'ThisWorkbook.Worksheets("Sheet55").Range("A1").Value = 10

On Error GoTo Err_XYZ
ThisWorkbook.Worksheets("Sheet66").Range("A1").Value = 10

MsgBox "You made it to here? Wow!"

Exit Sub

Err_XYZ:
With Err
.Raise .Number
End With
End Sub

干杯,-WWC

© www.soinside.com 2019 - 2024. All rights reserved.