【问题标题】:VBA Error Handler with "With" Statement带有“With”语句的 VBA 错误处理程序
【发布时间】:2015-04-27 19:56:36
【问题描述】:

如果不设置标签,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”行恢复。问题是它仍然在 CommentRST 是空的“With”语句中。有没有办法告诉错误处理程序在“With RST”行或“.AddNew”行恢复而不在“With”语句之前创建标签或首先检查空白记录集?

我知道有一些方法可以解决这个问题(正如我刚刚建议的其中 2 个),但我很好奇这是否可行。

【问题讨论】:

  • 添加前为什么不检查记录集?
  • 您是否这样处理它是因为您调用.AddNew 时您的顶部rst 可能未打开?
  • @Brad 为什么选择 ADO 和 MS Access? stackoverflow.com/questions/2631678/vba-check-if-object-is-set
  • 你在问是否有类似Resume Previous的东西(没有)。代码按顺序执行,并且在没有明确被告知要去哪里的情况下不会“倒退”或回到之前的某个点。在这种情况下,编译器如何知道With 块的开头(而不是在其他点)恢复?

标签: ms-access vba


【解决方案1】:

只需向 SetRST 添加一个 byRef 参数。

例如:

Sub SetRST(byref myrs as recordset)
   'do stuff
   set myrs = ...

顺便说一句,您的错误处理示例很糟糕:只需在 ErrHand: 之前添加一个 Exit Sub
所以你不需要测试err.number&lt;&gt;0,因为你知道它永远都是。

在你的错误处理中,使用:

call SetRST rst

编辑:
我更喜欢这样的东西:

If rst Is Nothing Then
    Set rst = something
End if
With rst
   'continue here

【讨论】:

  • 我的Rubberduck VBE add-inCall SetRST rst 行上说“使用过时的通话声明”;)
  • 我从来不写'Call',这没什么用,我只是写在这里保持asker的风格。你是对的,它没用而且(因此)不雅。
  • 抱歉代码混乱。我知道编写的代码不会打开记录集。然而,这不是我遇到的问题。即使我添加了 ByRef 参数,这仍然不起作用,因为当错误处理程序恢复时,它仍然会在引用 Nothing 记录集的“.AddNew”行上恢复。
  • @OpiesDad:会的
  • 我喜欢你。如果您厌倦了 SO,我们可以随时使用 more VBA Reviewers on Code Review
【解决方案2】:

在这种情况下,编译器如何知道在 With 块的开头恢复(而不是在其他点)?它不会,尽管它可能是逻辑连接的(即它在With 块内),但仍然没有理由按照规则假设执行应该在该块的开始处恢复,而无需在该点明确引用恢复。

您要问的内容基本上假设了错误的来源,然后期望 VBA 内置了这个假设,但它肯定不适用于所有甚至大多数情况,请考虑下面,假设 rst 是打开/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

如果错误发生在与错误处理程序相同的过程中,则从导致错误的语句继续执行。如果错误发生在被调用的过程中,则从包含错误处理例程的过程中最后调用的语句处继续执行。

Resume Next:

如果错误发生在与错误处理程序相同的过程中,则从导致错误的语句之后的语句继续执行。如果错误发生在被调用的过程中,则从包含错误处理例程(或 On Error Resume Next 语句)的过程中最后调用的语句之后的语句继续执行。

Resume &lt;line&gt;

在所需行参数中指定的行恢复执行。 line 参数是行标签或行号,并且必须与错误处理程序在同一过程中。

【讨论】:

    【解决方案3】:

    With 块持有一个对象的实例,并在End With 释放它。如果你跳出With 块,对象就消失了。

    所以答案是否定的,你不能 Resume 进入 With 块的中间。 其实你可以,但事情变得丑陋和混乱。 em>

    这是您在此处使用的 With 语句的常见误用 - 您只是因为懒惰而使用它(无意冒犯),并且不想在每个前面输入 rst.使用该对象的行。

    正确使用会使With本身 持有引用,如下所示:

    With GetRecordset 'a function that returns a recordset
        .AddNew
        !MyValue = 1
        .Update
        .Bookmark = .LastModified
        .Close
    End With
    

    ..我不建议使用这样的记录集,但你明白了 ;)

    【讨论】:

    • 可以Resume 放入 with 块中,只要错误处理程序不执行 End With
    • @DavidZemens 哎哟!我宁愿保持我的纯真,相信你不能那样做……那味道不是很糟糕吗?
    猜你喜欢
    • 2016-03-10
    • 2012-05-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-17
    • 1970-01-01
    • 2021-06-25
    相关资源
    最近更新 更多