恢复旧 VBA 错误
Restoring Old VBA On Error
假设您在主子中定义了 On Error。
Sub Main()
On Error Goto CatchAll
'... Some code... goes here
Call XYZ
CatchAll:
Msgbox "An Unexpected Error Occurred"
End
End Sub
在 Main sub 中,您调用了例程 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 error 的最后一个行为(上一个行为:Goto Main.CatchAll 标签,新行为,Goto XYZ.Errorz 标签)。在代码的这一点上,我希望能够在错误时转到 Main.CatchAll。
有什么方法可以做到这一点吗?
是的,在 XYZ()
On Error Goto 0
应该清除当前过程的(即 XYZ() 的)错误处理程序,并在您的示例中将错误处理的控制权传递给 Main() 中的错误处理程序。
当然可以。除了直接 ,您可以有条件地 重新抛出 处理程序中的错误:
Errorz:
With Err
If .Number = SomeSpecificLocalError Then
' mitigate error
Resume Next
Else
' rethrow
.Raise .Number
End If
End With
这样可以保留原始错误消息(您可以选择指定 source
和更具描述性的 message
供 "catch-all" 处理程序查看)和 "bubble"调用堆栈出错。
让我们用另一种语言来说明区别:
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
如果你必须有一个 in 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
假设您在主子中定义了 On Error。
Sub Main()
On Error Goto CatchAll
'... Some code... goes here
Call XYZ
CatchAll:
Msgbox "An Unexpected Error Occurred"
End
End Sub
在 Main sub 中,您调用了例程 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 error 的最后一个行为(上一个行为:Goto Main.CatchAll 标签,新行为,Goto XYZ.Errorz 标签)。在代码的这一点上,我希望能够在错误时转到 Main.CatchAll。
有什么方法可以做到这一点吗?
是的,在 XYZ()
On Error Goto 0
应该清除当前过程的(即 XYZ() 的)错误处理程序,并在您的示例中将错误处理的控制权传递给 Main() 中的错误处理程序。
当然可以。除了直接
Errorz:
With Err
If .Number = SomeSpecificLocalError Then
' mitigate error
Resume Next
Else
' rethrow
.Raise .Number
End If
End With
这样可以保留原始错误消息(您可以选择指定 source
和更具描述性的 message
供 "catch-all" 处理程序查看)和 "bubble"调用堆栈出错。
让我们用另一种语言来说明区别:
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
如果你必须有一个 in 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