VBA 带有 "With" 语句的错误处理程序
VBA Error Handler with "With" Statement
如果不设置标签,VBA 错误处理程序是否可以在 With 语句的开头恢复?
例如:
Dim rst As DAO.Recordset
Set rst = Nothing
On Error GoTo ErrHand
With rst
.AddNew
!MyValue = 1
.Update
.Bookmark = .LastModified
End With
ErrHand:
If Err.Number <> 0 Then
Call SetRST 'Assume this procedure opens the recordset appropriately
Resume
End If
End Sub()
该代码将在“.AddNew”行上导致错误,然后当它通过错误处理程序时将设置记录集,但随后它将在“.AddNew”行上恢复。问题是它仍然在 "With" 语句中,其中 CommentRST 是空的。有没有办法告诉错误处理程序在 "With RST" 行而不是在“.AddNew”行恢复而不在 "With" 语句之前创建标签或首先检查空白记录集?
我知道有解决方法(我刚刚建议了其中的 2 个),但我很好奇这是否可行。
一个With
块持有一个对象的实例,并在End With
释放它。如果你跳到 With
块之外,对象就消失了。
所以答案是否定的,你不能Resume
进入With
块的中间。 其实你可以,但事情变得丑陋和混乱。
这是对您在此处的 With
声明的一种常见误用 - 您只是因为懒惰(无意冒犯)而使用它,并且不想输入 rst.
在使用该对象的每一行前面。
正确使用 With
块 本身 保存引用,如下所示:
With GetRecordset 'a function that returns a recordset
.AddNew
!MyValue = 1
.Update
.Bookmark = .LastModified
.Close
End With
..并不是说我会推荐使用这样的记录集,但你明白了 ;)
只需将 byRef 参数添加到 SetRST。
例如:
Sub SetRST(byref myrs as recordset)
'do stuff
set myrs = ...
顺便说一下,您的错误处理示例很糟糕:只需在 ErrHand:
、
之前添加一个 Exit Sub
所以你不需要测试是否 err.number<>0
,因为你知道它永远是。
在您的错误处理中,使用:
call SetRST rst
编辑:
我更喜欢这样的东西:
If rst Is Nothing Then
Set rst = something
End if
With rst
'continue here
在这种情况下,编译器如何知道在 With 块的开头(而不是在其他点)恢复?它不会,虽然它可能在逻辑上是连接的(即,它在 With
块内),但仍然没有理由根据规则假设执行应该在该块的开始处恢复,而没有明确引用恢复观点。
你问的基本上是假设错误的来源,然后期望 VBA 内置了这个假设,但它肯定不适用于所有甚至大多数情况,请考虑下面,假设 rst
是 open/etc,实际错误在 Bookmark
属性 出现,您的错误处理程序没有考虑到这一点,因此在块将导致无限失败循环!
On Error GoTo ErrHand
With rst
.AddNew
!MyValue = 1
.Update
.Bookmark = "George Washington"
End With
请参阅有关 Resume
语句的文档:
https://msdn.microsoft.com/en-us/library/office/gg251630.aspx
你有选择Resume
If the error occurred in the same procedure as the error handler, execution resumes with the statement that caused the error. If the error occurred in a called procedure, execution resumes at the statement that last called out of the procedure containing the error-handling routine.
或Resume Next
:
If the error occurred in the same procedure as the error handler, execution resumes with the statement immediately following the statement that caused the error. If the error occurred in a called procedure, execution resumes with the statement immediately following the statement that last called out of the procedure containing the error-handling routine (or On Error Resume Next statement).
或Resume <line>
Execution resumes at line specified in the required line argument. The line argument is a line label or line number and must be in the same procedure as the error handler.
如果不设置标签,VBA 错误处理程序是否可以在 With 语句的开头恢复?
例如:
Dim rst As DAO.Recordset
Set rst = Nothing
On Error GoTo ErrHand
With rst
.AddNew
!MyValue = 1
.Update
.Bookmark = .LastModified
End With
ErrHand:
If Err.Number <> 0 Then
Call SetRST 'Assume this procedure opens the recordset appropriately
Resume
End If
End Sub()
该代码将在“.AddNew”行上导致错误,然后当它通过错误处理程序时将设置记录集,但随后它将在“.AddNew”行上恢复。问题是它仍然在 "With" 语句中,其中 CommentRST 是空的。有没有办法告诉错误处理程序在 "With RST" 行而不是在“.AddNew”行恢复而不在 "With" 语句之前创建标签或首先检查空白记录集?
我知道有解决方法(我刚刚建议了其中的 2 个),但我很好奇这是否可行。
一个With
块持有一个对象的实例,并在End With
释放它。如果你跳到 With
块之外,对象就消失了。
所以答案是否定的,你不能 其实你可以,但事情变得丑陋和混乱。Resume
进入With
块的中间。
这是对您在此处的 With
声明的一种常见误用 - 您只是因为懒惰(无意冒犯)而使用它,并且不想输入 rst.
在使用该对象的每一行前面。
正确使用 With
块 本身 保存引用,如下所示:
With GetRecordset 'a function that returns a recordset
.AddNew
!MyValue = 1
.Update
.Bookmark = .LastModified
.Close
End With
..并不是说我会推荐使用这样的记录集,但你明白了 ;)
只需将 byRef 参数添加到 SetRST。
例如:
Sub SetRST(byref myrs as recordset)
'do stuff
set myrs = ...
顺便说一下,您的错误处理示例很糟糕:只需在 ErrHand:
、
之前添加一个 Exit Sub
所以你不需要测试是否 err.number<>0
,因为你知道它永远是。
在您的错误处理中,使用:
call SetRST rst
编辑:
我更喜欢这样的东西:
If rst Is Nothing Then
Set rst = something
End if
With rst
'continue here
在这种情况下,编译器如何知道在 With 块的开头(而不是在其他点)恢复?它不会,虽然它可能在逻辑上是连接的(即,它在 With
块内),但仍然没有理由根据规则假设执行应该在该块的开始处恢复,而没有明确引用恢复观点。
你问的基本上是假设错误的来源,然后期望 VBA 内置了这个假设,但它肯定不适用于所有甚至大多数情况,请考虑下面,假设 rst
是 open/etc,实际错误在 Bookmark
属性 出现,您的错误处理程序没有考虑到这一点,因此在块将导致无限失败循环!
On Error GoTo ErrHand
With rst
.AddNew
!MyValue = 1
.Update
.Bookmark = "George Washington"
End With
请参阅有关 Resume
语句的文档:
https://msdn.microsoft.com/en-us/library/office/gg251630.aspx
你有选择Resume
If the error occurred in the same procedure as the error handler, execution resumes with the statement that caused the error. If the error occurred in a called procedure, execution resumes at the statement that last called out of the procedure containing the error-handling routine.
或Resume Next
:
If the error occurred in the same procedure as the error handler, execution resumes with the statement immediately following the statement that caused the error. If the error occurred in a called procedure, execution resumes with the statement immediately following the statement that last called out of the procedure containing the error-handling routine (or On Error Resume Next statement).
或Resume <line>
Execution resumes at line specified in the required line argument. The line argument is a line label or line number and must be in the same procedure as the error handler.