假设你的主子中有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。
有没有办法实现这个目标?
是的,在XYZ()中
On Error Goto 0
应该清除当前过程的(即XYZ()的)错误处理程序,并在您的示例中将错误处理的控制传递给Main()中的错误处理程序。
当然。没有直接的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:您的程序可能会导致太多事情,将其拆分。
这很容易踢回到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
如果你必须有一个子错误处理程序,当使用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