Excel VBA:错误 Goto 语句在 For-Loop 中不起作用

Posted

技术标签:

【中文标题】Excel VBA:错误 Goto 语句在 For-Loop 中不起作用【英文标题】:Excel VBA: On Error Goto statement not working inside For-Loop 【发布时间】:2012-08-13 11:47:51 【问题描述】:

我正在尝试循环浏览 Excel 中的表格。该表的前三列有文本标题,其余的有日期作为标题。我想将这些日期按顺序分配给一个日期类型的变量,然后根据日期执行一些操作

为此,我在 myTable.ListColumns 上使用了 foreach 循环。由于前三列没有日期标题,我尝试设置循环,以便在将标题字符串分配给日期类型变量时出错,循环直接进入下一列

这似乎适用于第一列。但是,当第二列的标题被“分配”给日期类型变量时,宏会遇到错误,即使它位于错误处理块中

Dim myCol As ListColumn
For Each myCol In myTable.ListColumns
    On Error GoTo NextCol

    Dim myDate As Date
    myDate = CDate(myCol.Name)

    On Error GoTo 0

    'MORE CODE HERE

NextCol:
    On Error GoTo 0
Next myCol

重申一下,错误是在循环的第二轮语句中抛出的

myDate = CDate(myCol.Name)

谁能解释为什么 On Error 语句停止工作?

【问题讨论】:

与其使用错误作为控制结构,也许在这种情况下使用带有 IsDate 函数的 IF 会更合适? 如果您“盲目地”处理错误 - 而不是对错误类型采取特定操作 - 那么您应该在循环外使用 On Error Resume Next 。目前,您正在对每一列重新使用错误处理。 @brettdj,我不认为你可以继续下一个。如果日期转换失败,整个想法是跳过“更多代码”代码。所以你需要进入一个处理程序,以便你可以恢复到特定的行。此外,您只希望为日期转换启用处理程序,而不是整个循环体。 @paxdiablo 经过反思,我同意。我想在此处查看“更多代码”。 【参考方案1】:

使用显示的代码,当您敲击next 语句时,您实际上仍被视为错误处理例程中。

这意味着在您从当前错误处理程序恢复之前,不允许后续错误处理程序。

更好的架构是:

    Dim myCol As ListColumn
    For Each myCol In myTable.ListColumns
        On Error GoTo ErrCol
        Dim myDate As Date
        myDate = CDate(myCol.Name)
        On Error GoTo 0
        ' MORE CODE HERE '
NextCol:
    Next myCol
    Exit Sub ' or something '

ErrCol:
    Resume NextCol

这清楚地描述了常规代码中的错误处理,并确保当前执行的错误处理程序在您尝试设置另一个处理程序之前完成。

This site 很好地描述了问题:


错误处理块和错误转到

错误处理块,也称为错误处理程序,是通过On Error Goto <label>: 语句将执行转移到的代码段。此代码应设计为解决问题并在主代码块中恢复执行或终止过程的执行。您不能仅跳过行来使用On Error Goto <label>: 语句。比如下面的代码就不能正常工作:

    On Error GoTo Err1:
    Debug.Print 1 / 0
    ' more code
Err1:
    On Error GoTo Err2:
    Debug.Print 1 / 0
    ' more code
Err2:

当出现第一个错误时,执行转移到Err1: 之后的行。当第二个错误发生时,错误处理程序仍然处于活动状态,因此On Error 语句不会捕获第二个错误。

【讨论】:

“更好的架构”应该是...比跳过错误更好的错误处理技术 :) @enderland:嗯,是的,这可能更可取,但是“当魔鬼吐到你的水壶里时需要”:-) @brettdj,我不太确定。您只希望在数据转换期间启用错误处理程序,在“这里有更多代码”的位中。 @paxdiablo 你说得很对。虽然我认为在整个过程中进行错误处理会更有意义,然后测试触发的错误条件以判断如何处理它。 +1 顺便说一句【参考方案2】:

您需要在错误处理代码中添加某种resume 以指示错误处理已结束。否则,第一个错误处理程序仍然处于活动状态,您永远不会“解决”。

见http://www.cpearson.com/excel/errorhandling.htm(特别是标题“错误处理块和错误转到”和以下部分)

【讨论】:

【参考方案3】:

跟进 paxdiablo 接受的答案。这是可能的,允许在同一个 sub 中有两个错误陷阱,一个接一个:

Public Sub test()
    On Error GoTo Err1:
    Debug.Print 1 / 0
    ' more code
Err1:
    On Error GoTo -1     ' clears the active error handler
    On Error GoTo Err2:  ' .. so we can set up another
    Debug.Print 1 / 0
    ' more code
Err2:
    MsgBox "Got here safely"
End Sub

使用On Error GoTo -1 会取消活动的错误处理程序并允许设置另一个错误处理程序(而err.clear 不会这样做!)。这是否是一个好主意留给读者作为练习,但它确实有效!

【讨论】:

谢谢。很有帮助。实际上,在循环上,您需要重置错误处理...【参考方案4】:

清除 Err 对象的所有属性设置与重置错误处理程序不同。

试试这个:

Sub TestErr()
Dim i As Integer
Dim x As Double
    On Error GoTo NextLoop
    For i = 1 To 2
10:     x = i / 0
NextLoop:
        If Err <> 0 Then
            Err.Clear
            Debug.Print "Cleared i=" & i
        End If
    Next
End Sub

你会注意到就像 OP 一样,它会在 i =1 时正确捕获错误,但在 i = 2 时它会在第 10 行失败,即使我们使用了 Err.Clear

【讨论】:

以上是关于Excel VBA:错误 Goto 语句在 For-Loop 中不起作用的主要内容,如果未能解决你的问题,请参考以下文章

Excel VBA中for循环语句的用法

Excel VBA中for循环语句的用法

如何在Excel,VBA中执行SQL语句?

Excel VBA结束选择没有选择案例

Excel VBA 错误:在没有 For 的情况下下一个编译错误

Excel VBA循环