我正在尝试通过以下方式在Excel宏中使用“And”实现惰性求值:
If Not myObject Is Nothing *And* myObject.test() Then
'do something'
Else
'do something else'
End If
我知道VB.NET中存在惰性求值,如AndAlso
和OrElse
,但在VBA中找不到类似的东西。如果VBA中不存在惰性求值,那么结构化代码的最佳方法是什么,以便它按照我的期望进行评估?
我正在尝试通过以下方式在Excel宏中使用“And”实现惰性求值:
If Not myObject Is Nothing *And* myObject.test() Then
'do something'
Else
'do something else'
End If
我知道VB.NET中存在惰性求值,如AndAlso
和OrElse
,但在VBA中找不到类似的东西。如果VBA中不存在惰性求值,那么结构化代码的最佳方法是什么,以便它按照我的期望进行评估?
唯一的短路(某种程度上)发生在Case
表达式求值中,因此下面的笨拙语句实现了我认为你想要的功能;
在Case
表达式求值中,存在一种特殊的短路机制。因此,下面这个冗长的语句会实现你所需求的功能:
Select Case True
Case (myObject Is Nothing), Not myObject.test()
MsgBox "no instance or test == false"
Case Else
MsgBox "got instance & test == true"
End Select
End Sub
OrElse
会从右到左评估条件。这是你的意思吗?因为我认为事实并非如此。 - ElRudi这是一个老问题,但是这个问题仍然存在。我使用过的一个解决方法是:
Dim success As Boolean ' False by default.
If myObj Is Nothing Then ' Object is nothing, success = False already, do nothing.
ElseIf Not myObj.test() Then ' Test failed, success = False already, do nothing.
Else: success = True ' Object is not nothing and test passed.
End If
If success Then
' Do stuff...
Else
' Do other stuff...
End If
这基本上是颠倒了原问题的逻辑,但得到了相同的结果。我认为这比其他仅使用If
语句的解决方案更加简洁。使用Select
语句的解决方案很聪明,但如果你想要只使用If
语句的替代方案,我认为这是一个可以使用的方案。
ElseIf
是 VBA 的一部分,而不是宿主程序的一部分。它可以在任何宿主程序中使用,包括所有版本的 Word。你可能犯了其他错误。 - HackSlashif Proceed(objMyAwesomeObject) then
'do some really neat stuff here
else
'do something else, eh
end if
...
end sub
private function Proceed(objMyAwesomeObject as Object)
if not objMyAweseomeObject is nothing then
Proceed = true
elseif objMyAwesomeObject.SomeProperty = SomeValue then
Proceed = true
else
Proceed = false
endif
end function
Not objMyAwesomeObject Is Nothing
评估为 True
,那么第一个 ElseIf
语句将永远不会执行。但是,如果 Not objMyAwesomeObject Is Nothing
= False (objMyAwesomeObject Is Nothing
= True),则第一个 ElseIf
语句将执行并引发错误,因为您正在尝试访问 Is Nothing
上的 objMyAwesomeObject
属性。 - neizandim conditionsValid as boolean
conditionsValid = Not myObject Is Nothing
if conditionsValid then conditionsValid = myObject.test()
if conditionsValid then conditionsValid = myObject.anotherTest()
if conditionsValid then
'do something'
else
'do something else'
end if
conditionsValid = Not myObject Is Nothing
。提议的动作“做其他事情”更应该是“进行错误处理”,在你的例子中两个动作听起来是一样的。具体情况可能有所不同。 - user1016274Dim passed, wrongMaxPercent, wrongPercent, rightMinPercent, rightPercent
wrongPercent = 33
rightPercent = 55
'rightMinPercent = 56
wrongMaxPercent = 40
passed = (Len(wrongMaxPercent) = 0 Or wrongPercent < wrongMaxPercent) And _
(Len(rightMinPercent) = 0 Or rightPercent >= rightMinPercent)
由于以下语法有效
If myObject.test() Then do something
然后可以使用一行代码来短路评估。下面,第一个If
语句确保myObject
是某个东西。否则,它甚至不会尝试评估第二个If
。
If Not myObject Is Nothing Then If myObject.test() Then
'do something'
Else
'do something else'
End If
当然,如果您想在 myObject 为空时执行其他操作,那么这种方法可能不适用。
更新于2020/06/30
在一条评论指出这个答案不起作用后,我验证了语法似乎在现代VBA中无法使用。为了遗留目的保留原始答案。
If
,一个是用于Not myObject Is Nothing
,另一个是用于myObject.test()
。但是,由于第一个If
语句采用了一行格式,因此第一个If
的内容(也就是第二个If
)不能超过一行。 - Sreenikethan IIf Not myObject Is Nothing Then
If myObject.test() Then
'do something'
End If
Else
'do something else'
End If
我认为这是你必须这样做的方式。
编辑
也许像这样
Dim bTestsFailed as Boolean
bTestsFailed = False
If Not myObject Is Nothing Then
If myObject.test() Then
'do something'
Else
bTestsFailed = True
End If
Else
bTestsFailed = True
End If
If bTestsFailed Then
'do something else
End If
VBA不是很棒吗?
myObject
不是空值但myObject.test()
返回False时,发生其他事情
。 - BenVErr.Clear
On Error Resume Next
If myObject Is Nothing Or Not myObject.test() Then
Err.Clear
'do something else'
Else
'do something'
End If
On Error Goto 0 ' or On Error Goto ErrorHandler (depending on previous setting in the code)
对于 Nothing
的测试是不必要的 - 它只是为了澄清意思。
我不知道有没有与OrElse
等效的东西,但是对于AndAlso
,有一个有限但有用的解决方案。以下两个是等效的:
If Condition1 AndAlso Condition2 Then DoSomething
If Condition1 Then If Condition2 Then DoSomething
它有两个限制:
Else
块不会被执行,只有在第一个条件为true且第二个条件为false时才会执行即使考虑到这两个相当严重的限制,当我没有Else
块时,我经常使用这个小技巧。
以下是一个示例:
Sub Test()
Dim C As Collection
' This is what I often use
If Not C Is Nothing Then If C.Count Then DoSomethingWith C
' Here are other usages I stay away from, because of bad readability
If Not C Is Nothing Then If C.Count Then Debug.Print "not empty" Else Debug.Print "empty or nothing"
Set C = New Collection
If Not C Is Nothing Then If C.Count Then Debug.Print "not empty" Else Debug.Print "empty or nothing"
C.Add 1
If Not C Is Nothing Then If C.Count Then Debug.Print "not empty" Else Debug.Print "empty or nothing"
End Sub```