由于答案是谷歌排名靠前的之一,只需要搜索类似于 vba if condition not lazy
的东西,我想提供一个更简单的例子,解决方案和问题都包括两种条件:AND
和更有趣的 OR
...
Dim cond1 As Boolean 'some 1st condition that may be True or False
Dim obj As Collection 'just some sample object that may or may not be instantiated
(²:如果其他开发人员不知道背景,我觉得更好的方法是解释你为什么没有选择OR
)
AND
案例
cond1 = False
If cond1 Then Set obj = New Collection
问题:
If cond1 And obj.Count > 0 Then Debug.Print "Count > 0!" 'throws error if < cond1 = False >
'because condition 2 is always evaluated
解决方案:
If cond1 Then If obj.Count > 0 Then Debug.Print "Count > 0!" 'AND would not short-cicuit!² https://dev59.com/7Ww05IYBdhLWcg3w0U8O#57521572
根据口味、复杂度和可读性,写成这样可能更有意义:
If cond1 Then
If obj.Count > 0 Then 'AND would not short-cicuit!² https://dev59.com/7Ww05IYBdhLWcg3w0U8O#57521572
Debug.Print "Count > 0!"
End If
End If
OR
情况
cond1 = True
If Not cond1 Then Set obj = New Collection 'obj stays < Nothing > otherwise
问题:
If cond1 Or obj.Count = 0 Then Debug.Print "no objects!" 'throws error if < cond1 = True >
'because condition 2 is always evaluated
解决方案1:
使用
Select
,在原地进行操作,不冗余,一行代码,无需使用
GoTo
。
Select Case True: Case cond1, obj.Count = 0: Debug.Print "no objects!": End Select 'OR would not short-cicuit!² https://dev59.com/7Ww05IYBdhLWcg3w0U8O#57521572
如果需要跨越多行并且还有其他内容:
Select Case True
Case cond1, obj.Count = 0 'OR would not short-cicuit!² https://dev59.com/7Ww05IYBdhLWcg3w0U8O#57521572
Debug.Print "no objects!"
Case Else
Debug.Print "object count: " & obj.Count
End Select
解决方案2:
就地修改,不冗余的代码,最小化使用GoTo
,但使用更多的长If
多行代码:
If cond1 Then
noObjs:
Debug.Print "no objects!"
ElseIf obj.Count = 0 Then 'OR would not short-cicuit!² https://dev59.com/7Ww05IYBdhLWcg3w0U8O#57521572
GoTo noObjs
End If
解决方案3:
原地修改,在一行上使用类似于OR
连接的条件(可能适用),并且使用了相当多的GoTo
。
If cond1 Then GoTo noObjs ElseIf obj.Count = 0 Then GoTo noObjs 'OR would not short-cicuit!² https://dev59.com/7Ww05IYBdhLWcg3w0U8O#57521572
GoTo skipOnAllFalse
noObjs:
Debug.Print "no objects!"
skipOnAllFalse: 'use more specific label/scenario name if possible
解决方案4:
避免使用GoTo
,将条件(如果适用)放在一行上,但模块/类代码可能更难以阅读/散乱/混乱。
Private Sub noObjs(): Debug.Print "no objects!"
If cond1 Then noObjs ElseIf obj.Count = 0 Then noObjs 'OR would not short-cicuit!² https://dev59.com/7Ww05IYBdhLWcg3w0U8O#57521572
解答:
解决方案 5:
使用一个条件变量:
Dim any As Boolean: any = cond1
If Not any Then any = obj.Count = 0 'OR would not short-cicuit!² https://dev59.com/7Ww05IYBdhLWcg3w0U8O#57521572
If any Then Debug.Print "no objects!"
解决方案6:
使用多个条件变量:
Dim c1 As Boolean: Dim c2 As Boolean
c1 = cond1
If Not c1 Then c2 = obj.Count = 0 'OR would not short-cicuit!² https://dev59.com/7Ww05IYBdhLWcg3w0U8O#57521572
If c1 Or c2 Then Debug.Print "no objects!" 'safe to use Or now
And
运算符不会短路,因为它是一个按位运算符,而不是逻辑运算符。参见:https://dev59.com/clzUa4cB1Zd3GeqP8f6f#8047021 - jtolleOr
的左侧参数是 "all 1s" (&HFFFFFFFF
或-1&
),则右侧参数也可以被跳过,同样适用于And
如果左侧参数为 0。 - Hugh Allen