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.