【问题标题】:Using On Error Resume Next with If statements将 On Error Resume Next 与 If 语句一起使用
【发布时间】:2017-05-09 17:01:34
【问题描述】:

由于 On Error Resume Next 继续执行下一条语句而不是下一行,是否有人对将它与 If 语句一起使用有任何建议?

On Error Resume Next
For i = 1 To r
    If dataArray(i,1) <10 Then
        intA = intA + 1
    End If
    If dataArray(i,2) <10 Then intB = intB + 1
    If dataArray(i,2) <10 Then _
        intC = intC + 1: intD = intD + 1
Next i
On Error GoTo 0

上面每种风格的If语句,在出错的情况下依然会进行加法,比如元素dataArray(i,1)包含文本。这可以通过错误处理程序来解决,但如果有多个 If 语句,这会变得混乱。有人有什么建议吗?

【问题讨论】:

  • 你能更好地解释你想要达到的目标吗?以及您在哪里得到错误(不使用On Error Resume Next)。有时最好捕获并处理您的错误)
  • 您可以随时添加额外的测试If Err.Number = 0,也可以在适当的情况下使用Err.Clear 之类的语句。但是,您不应该大量依赖 On Error Resume Next 机制,它只是一个非常方便的“技巧”,但如果您真的想在您的代码中到处依赖它,您真的应该重新考虑这个决定。
  • 例如在上面的代码中,如果变量不能保证是数字,一个好的代码应该先用IsNumeric测试它而不是指望错误处理,因为后者不是flow control 指令。
  • @A.S.H; IsNumeric() 函数必须有意识地处理。例如 IsNumeric("1,.23") 会返回 True... 所以我只在我知道我有“声音”数据时才使用它,即 real 数字或文本。如果 OP 的 dataArray 来自 range,那么安全的方法是 first 使用 SpecialCells() 过滤 number 单元格并 then 填充数组并操作其数据
  • @A.S.H,我同意,我没有反驳你评论的那部分。此外,SpecialCells() 方法正朝着这个方向发展。我只是指出了一个微妙的IsNumeric() 陷阱!

标签: arrays vba excel error-handling


【解决方案1】:

严格对您的问题的回答如下:

Option Explicit

Sub main()
    Dim dataArray As Variant
    Dim i As Long, r As Long, intA As Long, intB As Long, intC As Long, intD As Long

    dataArray = Range("A1:D5").Value
    r = UBound(dataArray)
    On Error GoTo SKIP
    For i = 1 To r
        If dataArray(i, 1) < 10 Then intA = intA + 1

        If dataArray(i, 2) < 10 Then
            intB = intB + 1
            intC = intC + 1
            intD = intD + 1
        End If
SKIP:
    Next i
    ' On Error GoTo 0 '<--| you can comment this out being the last statement since upon exiting the default error handling is resumed 

End Sub

【讨论】:

  • 本着我们在 cmets 领域讨论的精神,但最好也包括您建议的 SpecialCells idiom。
  • @A.S.H,我很乐意,但使用真实的数据结构来显示它会更有效
  • @user3598756 谢谢!顺便说一句,Err 值不需要通过 Resume 语句重置吗?我似乎记得读过,如果不这样做,Err 将保持为 0,这意味着 Err 不能被触发,后续的错误也不会被捕获。
【解决方案2】:

如果您希望数组指定位置上的数字值实际上不需要构建庞大的错误处理程序或使用 GoTo,您可以检查变量的Type! 所以,例如:

For i = 1 To r
    If IsNumeric(dataArray(i,1)) And Not IsString(dataArray(i,1)) Then
        If dataArray(i,1) <10 Then
            intA = intA + 1
        End If
        If dataArray(i,2) <10 Then intB = intB + 1
        If dataArray(i,2) <10 Then _
            intC = intC + 1: intD = intD + 1
    End If
Next i

Public Function IsString(ByRef var as Variant) as Boolean
    IsString = (TypeName(var) = "String")
End Function

如您所见,您可以检查IsNumeric,并且由于字符串可以是数字,因此显式检查Not IsString

由于不仅字符串可以从 IsNumeric 函数(例如字符)返回 True,因此还有办法修改示例并扩展您自己的函数!

链接: TypeName, IsNumeric

另一个示例(仅带一个小数点的数字并允许使用字符串)。 那么如果输入看起来像什么:

例子:

Sub AcceptOnlyNumbers()
'pass only strings that can be threaten as doubles
    Dim rng As Range
    Dim cl As Range

    Set rng = Sheets(1).[A1:A8]

    For Each cl In rng
        With cl
        If Not (IsNumeric(.Value2) Or (IsNumeric(Val(.Value2)) And _
            Len(.Value2) = Len(CStr(Val(.Value2))))) And .Value2 <> vbNullString Then
                Debug.Print .Value2, "is filtered"
            Else
                Debug.Print .Value2, "is passed"
            End If
        End With
    Next

End Sub

输出:

然后我们可以使用CDbl(如果十进制是逗号)或Val(如果十进制-点)转换字符串。随意玩弄它!例如,如果您不需要十进制数字,您可以在此之后添加另一个检查(或者,再次构建您自己的 - 所有这些只是示例,您可以在开始时检查整数):

Public Function IsWholeNumber(ByVal expDbl As Double) as Boolean
    IsWholeNumber = (Int(expDbl) = expDbl)
    'or more bulky but ok too: IsWholeNumber = InStr(Str(expDbl), ".") = 0
End Function

请注意这一事实,在点十进制国家CDbl 与点配合得很好,而我的示例则不同(带逗号的值也被过滤掉了)。

  • ValStr 将始终使用美国设置(点为十进制)。

  • CDblCStr 将考虑区域设置。

链接: Val, Writing International Code

【讨论】:

  • IsNumeric() 函数必须有意识地处理。例如IsNumeric("1,.23") 将返回True...所以我只在我知道我有“声音”数据时使用它,即真实数字或文本
  • @user3598756 因为没有数据示例,这只是一种无需错误处理程序即可完成的方法。但是,是的,你是对的,你给了一个很好的补充,但如果提问者期待你提到的事情 - 也很容易照顾他们!毕竟,正如我所提到的 - 提问者可以从它开始,构建自己的东西。我认为不仅仅是从 SO 中复制/粘贴答案更有趣,尤其是对于这类问题。
  • 我并不是说你的方法行不通。我只是添加一个关于可能存在的缺点的警告,并且(可能)既能增强你的答案,又能帮助人们阅读它
  • @user3598756,我知道,不用担心,正如我之前所说的 - 好的补充和好的警告,谢谢!而且我认为我对“为什么我是个混蛋”的解释也很清楚。
  • 毕竟"1,.23" 是一个字符串,所以我的回答可以解决这个问题。
猜你喜欢
  • 2011-01-13
  • 1970-01-01
  • 2017-03-25
  • 2017-10-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多