Есть ли способ оптимизировать вложенные предложения if? - PullRequest
0 голосов
/ 06 июля 2018

Некоторое время назад я пытался решить проблему снижения скорости в приложении Access при открытии предварительного просмотра некоторых отчетов. Я заметил, что медленные отчеты имеют одну общую черту - длинные, вложенные операторы if. Я попытался найти в Интернете ответ на этот вопрос, но некоторые решения не применимы к Access VBA или просто не могут быть реализованы в случае моего приложения.

Мне было интересно, существуют ли какие-либо общеизвестные способы, которые используются для того, чтобы избежать появления монстров?

РЕДАКТИРОВАТЬ: фрагмент кода - он в основном обрабатывает структуру отчета на основе определенных условий.

If (strCcDocNumber <> vbNullString) Then
    Dim strUpperPart As String, strLowerPart As String

    IDModule.placeIDStringsToPrivateVariables strCcDocNumber, ", "
    strUpperPart = IDModule.returnUpper()
    strLowerPart = IDModule.returnLower()

    txtIDs = strUpperPart & vbCrLf & strLowerPart
Else
    txtIDs = " " & vbCrLf & " "
End If

If (strOrderNumber = IO_OrderNumber.OrderNumberCode & "12345") Then
    txtIDs = txtIDs
    txtIDSpec1 = ModuleIDSpec1.getIDSpec1
    txtIDSpec2 = ModuleIDSpec2.getIDSpec2
    txtIDSpec1.Height = 330
    txtIDSpec2.Height = 330
    txtUpperLower = "- Ex" & vbCrLf & "- Ex2" & vbCrLf & vbCrLf & "- Ex3"
    On Error Resume Next
    For Each c In Me.Controls
        If (c.Tag = "IDSpec2Table" Or c.Tag = "IDSpec1Table") Then c.Height = 0
        If (c.Tag = "IDSpec2Table" Or c.Tag = "IDSpec1Table") Then c.Visible = False
        If (c.Tag = "IDSpec2Table" Or c.Tag = "IDSpec1TableExtra") Then c.Height = 0
        If (c.Tag = "IDSpec2Table" Or c.Tag = "IDSpec1TableExtra") Then c.Visible = False
        If (c.Tag = "IDSpec2Texts" Or c.Tag = "IDSpec1Texts") Then c.Visible = True
        If (c.Tag = "IDSpec2Texts" Or c.Tag = "IDSpec1Texts") Then c.Height = 330
        If (c.Tag = "IDSpec2Texts" Or c.Tag = "IDSpec1TextsExtra" And ModuleTarget.TargetGroup <> "23C") Then c.Visible = True
        If (c.Tag = "IDSpec2Texts" Or c.Tag = "IDSpec1TextsExtra" And ModuleTarget.TargetGroup <> "23C") Then c.Height = 330
        '+ many more tags
    Next
    On Error GoTo 0
    txtIDSpec1.Visible = True
    txtIDSpec2.Visible = True
    If (txtIDSpec1 = vbNullString And txtIDSpec2 = vbNullString) Then
        txtIDSpec1.Height = 0
        txtIDSpec2.Height = 0
        txtIDSpec1.Visible = False
        txtIDSpec2.Visible = False
    End If
Else
    '+a lot more similar conditions

РЕДАКТИРОВАТЬ: Я вспомнил, что, если заявления были самыми хлопотными. Я думаю, что вы не можете изменить их в отдельные случаи или в операторы ElseIf, потому что необходимо проверить все условия ...

Это выглядит так:

If (condition) Then
Do this
   If (differentCondition) Then
       Do this also
        If (completelyDifferentCondition) Then
            Do this as well
        Else
            Do this instead
        End If
   End If
Else
   If (yetAnotherCondition) Then
        Do this
   Else
        Do this instead
   End If
End If

Ответы [ 2 ]

0 голосов
/ 06 июля 2018

Мне было интересно, есть ли некоторые общеизвестные способы, которые используются в Чтобы избежать, если пункт монстров?

Первый шаг - понять, чего вы хотите достичь, а не того, как вы хотите это сделать. В этом контексте вы хотите установить высоту и видимость. Отсюда вы можете определить, какие условия необходимы для этого.

Когда вы в первый раз сделаете это, у вас появятся несколько предложений о монстрах - но это нормально, потому что вы не прояснили свое мышление. Работа из предположения об одном государстве, если не доказано иное. Вот пример:

c.visible = True
If ((c.Tag = "IDSpec2Table" Or c.Tag = "IDSpec1Table") OR (c.Tag = "IDSpec2Table" Or c.Tag = "IDSpec1TableExtra")) then c.visible = True

Конечно, теперь вторая строка может быть немного упрощена.

If (c.Tag = "IDSpec2Table" Or c.Tag = "IDSpec1Table" Or c.Tag = "IDSpec1TableExtra") then c.visible = True

Я также устанавливаю маркер Booleans - например:

IsSpecTable = (c.Tag = "IDSpec2Table" Or c.Tag = "IDSpec1Table")
IsMySpecialFriend = (c.Tag = "IDSpec1TextsExtra" And ModuleTarget.TargetGroup <> "23C")
[...]
c.Visible = IsSpecTable Or IsMySpecialFriend

Это пара методов, которые я использую для упрощения сложной бизнес-логики. Я также смотрю на использование флагов, но это означает преобразование текста Tag в перечисляемое значение (я делаю это в VB.Net). Этот метод, тем не менее, упрощает выражение до простой маски с оператором And или Or в зависимости от ситуации.

0 голосов
/ 06 июля 2018

Попробуйте использовать Select Case Statements, если у вас есть несколько If Statement на основе одного и того же значения.

MSDN - Выберите регистр

Выполняет одну из нескольких групп операторов в зависимости от значения выражения.

For Each c In Me.Controls
    Select Case c.Tag
    Case "IDSpec2Table", "IDSpec1Table", "IDSpec1TableExtra"
         c.Height = 0
         c.Visible = False
    Case "IDSpec2Texts", "IDSpec1Texts"
        c.Visible = True
        c.Height = 330
    Case "IDSpec1TextsExtra"
        If ModuleTarget.TargetGroup <> "23C" Then 
           c.Visible = True
           c.Height = 330
        End If
    End Select
Next

Производительность: выберите регистр против If против ElseIf

Я упомянул в комментарии, что использование Select Case больше для удобства чтения, чем для производительности. Что правильно, если мы сравниваем операторы Select Case и If ElseIf (читай Какой путь быстрее? Если еще, или выберите регистр ).

Select Case и If ElseIf могут быть значительно быстрее, чем несколько If операторов. Это связано с тем, что VBA оценивает каждое условие в операторе If и прекращает оценку, когда выполняется одно условие в операторе Select Case. Примечание: не все языки делают.

Рассмотрим этот простой тест.

Sub Test()
    Debug.Print "Test:If Statement Test:"
    If ret(1) = 1 Or ret(2) = 2 Or ret(3) = 3 Or ret(4) = 4 Or ret(5) = 5 Then

    End If

    Debug.Print vbNewLine; "Test:If ElseIf Statement"

    If ret(1) = 1 Or ret(2) = 2 Then

    ElseIf ret(3) = 3 Then

    ElseIf ret(4) = 4 Then

    ElseIf ret(5) = 5 Then

    End If

    Debug.Print vbNewLine; "Test:Select Case Statement"

    Select Case 1
        Case ret(1), ret(2)

        Case ret(3)

        Case ret(4)

        Case ret(5)

    End Select
End Sub

Function ret(n As Long) As Long
    ret = n
    Debug.Print n,
End Function

enter image description here

Обратите внимание, что оператор If должен был выполнить 5 операций, хотя все они были истинными. ElseIf пришлось выполнить 2 операции, потому что первые 2 операции были сгруппированы в одном предложении If. Select Case выполнил только одну операцию, хотя две операции были сгруппированы вместе. Это связано с тем, что Select Case всегда останавливает оценку условий, когда выполняется одно условие.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...