【问题标题】:AndAlso/OrElse in VBAVBA 中的 AndAlso/OrElse
【发布时间】:2011-03-15 15:04:24
【问题描述】:

我正在尝试通过执行以下操作在我的 Excel 宏中使用“和”进行惰性求值:

If Not myObject Is Nothing *And* myObject.test() Then
    'do something'
Else
    'do something else'
End If

我知道 VB.NET 中存在延迟评估,如 AndAlsoOrElse,但在 VBA 中找不到类似的东西。如果 VBA 中不存在惰性求值,那么构建代码以使其按我期望的方式求值的最佳方法是什么?

【问题讨论】:

  • VBA 像普通的 VB6 一样没有短路评估
  • 谢谢,我在没有解决方案的情况下解决了我的问题,但我仍然很好奇如何应对这种情况。如果我遗漏了一些非常明显的东西,我不会感到惊讶,但是如果不重写代码,我就找不到一个好方法来做到这一点,即在两种不同的 else 情况下使用相同的代码。

标签: vb.net vba


【解决方案1】:

可以切换逻辑条件,使用 Or 运算符并关闭错误消息,如下所示:

Err.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 测试不是必需的 - 它只是用来阐明含义。

【讨论】:

    【解决方案2】:

    由于以下语法有效

    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 语句是 one liner 格式,所以第一个 If(即第二个 If)的内容不能超过一行.
    • 我删除了第一个代码 sn-p,因为它演示了一个单行 If 语句。我在之前的评论中已经解释过,单行 Ifs 不能跨越多行! :D
    • 感谢建议的编辑,但答案中的语法是经过深思熟虑的。我更新了我的答案以更好地反映这一点。
    • 该示例甚至无法编译。有人如何支持这个答案?
    • @Cohan 但是这会很好;)感谢您的快速回答和更正。 VBA 的方式很神秘。
    【解决方案3】:

    关于缺失值的技巧可能会有所帮助:

    Dim 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)
    

    【讨论】:

    • 我相信你的代码是另一个程序的一部分......你能概括一下你的代码吗? (也就是把它做成可以适用于任何情况的形式)
    【解决方案4】:

    this answer 上改进关于同一基本问题的不同问题,这是我选择做的事情:

    dim conditionsValid as boolean
    
    conditionsValid = 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
    

    我认为此代码比已建议的其他答案更清晰,并且您(通常)不需要为每个验证使用不同的变量,这是对另一个问题的原始答案的改进。顺便说一句,您需要的每个新条件只增加一行代码。

    【讨论】:

      【解决方案5】:

      唯一的短路(某种)是在 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
      

      【讨论】:

      • 为了清楚起见,Case 中的逗号有点像“OrElse”,但它从左到右而不是从右到左检查条件。
      • @Wildhorn:“而不是从右到左” - 听起来好像 VB.NET 中的 OrElse 从右到左评估条件。这是你的意思吗?因为我不这么认为
      【解决方案6】:

      这是一个老问题,但这个问题仍然存在并且很好。我使用过的一种解决方法:

      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 在 Word 2016 VBA 中不起作用。
      • @CharlesW ElseIf 是 VBA 的一部分,而不是主机。它适用于每台主机,包括所有版本的 Word。你又犯了一些错误。
      • 同意! - 感谢您的更正!
      【解决方案7】:

      或者您可以创建一个函数,将您的对象作为参数并在任何一种情况下都返回布尔值。这就是我通常的做法。

      if 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 语句将执行并引发错误,因为您正试图访问 objMyAwesomeObject 上的属性,而 Is Nothing。跨度>
      【解决方案8】:
      If 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 不是很好吗?

      【讨论】:

      • 我认为他想让 else 条件也执行 if myObject Is Nothing,这意味着你必须复制 Else 'do something else'
      • @BenV,@Dick 我冒昧地编辑了(我相信)正确代码的答案。我同意 BenV
      • @MarkJ:我认为如果 myObject 不是 Nothing 但 myObject.test() 返回 False,他也希望 something else 发生。
      • 谢谢大家,你说得对,如果其中一个为假,我需要执行代码。这行得通,但我认为它有点难看;我喜欢“选择案例”解决方案,而不是为了清洁。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-06-13
      • 2012-03-03
      • 2018-02-07
      • 2012-01-14
      • 2010-09-08
      • 2023-04-10
      相关资源
      最近更新 更多