Excel VBA:在嵌套的if-else语句中创build“fall through”,还允许正常的行为?

在我的Excel VBAmacros中,我想尝试在嵌套的if-else语句中创build“fall through”。 但是我也希望能够像普通的if-else语句那样工作。

下面我的解决scheme似乎工作。 这种方法有什么问题吗?

我知道使用Goto是不被赞成的,但这是我能想到解决问题的唯一方法。

  If fallThrough = True Then GoTo Cr1 If fallThrough = False and criteria = crit1 Then Cr1: 'MsgBox "Criteria 1" ElseIf fallThrough = True Then GoTo Cr2 ElseIf fallThrough = False And criteria = crit2 Then Cr2: 'MsgBox "Criteria 2" If fallThrough = True Then GoTo Cr3 ElseIf fallThrough = False And criteria = crit3 Then Cr3: 'MsgBox "Criteria 3" If fallThrough = True Then GoTo Cr4 ElseIf fallThrough = False And criteria = crit4 Then Cr4: 'MsgBox "Criteria 4" End If 

做你想做的事情单独的潜艇,并在正常的情况下,如果他们打电话。

 Sub main(fallThrough As Boolean) If fallThrough Then critsub1 critsub2 critsub3 critsub4 Else If criteria = crit1 Then critsub1 ElseIf criteria = crit2 Then critsub2 ElseIf criteria = crit3 Then critsub3 ElseIf criteria = crit4 Then critsub4 End If End If End Sub Sub critsub1() MsgBox "Criteria 1" End Sub Sub critsub2() MsgBox "Criteria 2" End Sub Sub critsub3() MsgBox "Criteria 3" End Sub Sub critsub() MsgBox "Criteria 4" End Sub 

是的,你重复在这个电话,但这是更容易阅读和维护。

另一种方法是创build个人Ifs:

 If (Not fallThrough And criteria = crit1) Or fallThrough Then critsub1 If (Not fallThrough And criteria = crit2) Or fallThrough Then critsub2 If (Not fallThrough And criteria = crit3) Or fallThrough Then critsub3 If (Not fallThrough And criteria = crit4) Or fallThrough Then critsub4 

这样就没有重复了

除非绝对必要,否则我强烈build议避免使用GoTo ,如果您发现自己处于需要 GoTo的情况,那么find比您更有经验的人,他们会告诉您为什么没有。

GoTo有几个问题。 首先,它使我们能够创build更加懒惰和更低效的stream程来解决任务。 请记住,几乎任何任务都可以通过正确的逻辑组合来处理,只需要培训我们编写逻辑的能力即可。 编程是99%的逻辑,1%的代码。 这可能是对编程的一种简化的思考方式,但是大多数早期的编码问题可以通过无限多的低效率的方式解决,而且仍然有效,但是我们的任务是以正确的方式解决问题。

其次, GoTo很难看到你的代码真的在做什么。

那么,我们如何在没有GoTo情况下解决这个问题呢? 我们使用抽象

 Public Funtion CriteriaMatches(ByVal ControlCriteria as String, ByVal TestCriteria as String) as Boolean CriteriaMatches = (ControlCriteria = TestCriteria ) End Function 

然后,我们实现我们的function来减less第一层冗余:

 If fallThrough = True Then GoTo Cr1 If fallThrough = False and CriteriaMatches(criteria, crit1) Then Cr1: 'MsgBox "Criteria 1" ElseIf fallThrough = True Then GoTo Cr2 ElseIf fallThrough = False And CriteriaMatches(criteria, crit2) Then Cr2: 'MsgBox "Criteria 2" If fallThrough = True Then GoTo Cr3 ElseIf fallThrough = False And CriteriaMatches(criteria, crit3) Then Cr3: 'MsgBox "Criteria 3" If fallThrough = True Then GoTo Cr4 ElseIf fallThrough = False And CriteriaMatches(criteria, crit4) Then Cr4: 'MsgBox "Criteria 4" End If 

除了在函数调用中包装比较之外,这并没有做太多的工作,但是这里主要的好处是,如果ControlCriteria = TestCriteria成为ControlCriteria <> TestCriteria那么我们可以在一个地方做出这个改变。

接下来,如果我们的FallThrough = True ,我们需要一些允许函数返回FalseFallThrough 。 我们想返回一个False值的原因是因为如果FallThrough为true,我们想跳过这个动作。 这很简单:

 Public Funtion CriteriaMatches(ByVal ControlCriteria as String, ByVal TestCriteria as String, Optional byVal ReturnFalse as Boolean = False) as Boolean If ReturnFalse Then CriteriaMatches = (ControlCriteria = TestCriteria ) End Function 

由于Boolean函数的隐式返回BooleanFalse我们不需要添加一个If/Else块。

现在我们的代码变成:

 If CriteriaMatches(criteria, crit1, PassThrough) Then 'MsgBox "Criteria 1" ElseIf CriteriaMatches(criteria, crit1, PassThrough) Then 'MsgBox "Criteria 2" ElseIf CriteriaMatches(criteria, crit2, PassThrough) Then 'MsgBox "Criteria 3" ElseIf CriteriaMatches(criteria, crit3, PassThrough) Then 'MsgBox "Criteria 4" End If 

代码更加整洁,易于阅读,并且仍然以相同的方式执行(除了重复msgbox命令,这与标签的位置相关)。

我确信这个代码可以进一步减less(比如传入一个参数列表来比较,并且返回匹配的参数的位置),但是现在可以这样做。

这里的关键是学习新的代码模式,以帮助您解决以前无法解决的问题。 VBA有一个很好的理由模式和反模式,重要的是尽可能地避免它们的人为的可能性。

设置一个标志

设置一个标志是一个非常简单和可维护的方式来创造一个秋天通过:

 Dim Break As Boolean If Not Break And Condition1 Then 'Do Something End If If Not Break And Condition2 Then 'Do Something End If If Not Break And Condition3 Then 'Do Something Break = True 'Stop doing anything else End If If Not Break And Condition4 Then 'Do Something Break = True 'Stop doing anything else End If 

用于select案例的循环

虽然有点荒唐,但我认为这种模式最能模仿其他语言的Select语句。

 For i = 1 To 5 Select Case i Case 1 'Do Something Case 2 'Do Something Case 3 'Do Something Exit For ' Break Code Case 4 Exit For ' Break Code Case Else End Select Next i