Как безопасно удалить все операторы Option Base 1 из проекта VBA - PullRequest
3 голосов
/ 21 мая 2019

Я занимаюсь рефакторингом проекта VBA с около 100 модулями. Некоторые из модулей Option Base 1, другие Option Base 0 (по умолчанию). Я хотел бы, чтобы все модули были Option Base 0, поскольку это упрощает перемещение функций между модулями, чтобы они были более разумно расположены.

Я думаю, что я могу удалить все Option Base 1 операторов в проекте, если:

  1. Все операторы Dim и ReDim, которые устанавливают размерность массивов, имеют явные нижние границы.

  2. Я обращаю пристальное внимание на использование функции Array(), поскольку она вернет массив с нижней границей, определяемой Option Base модуля, в котором он находится.

Есть ли еще что-то, о чем мне нужно беспокоиться?

Ответы [ 2 ]

0 голосов
/ 22 мая 2019

Все, что пишет PEH, является правильным, особенно то, что внесение такого рода изменений требует тщательного анализа.

Это мое текущее состояние:

Код чувствителен к изменению оператора Option Base в верхней части модуля:

  • Dim MyArr(3) нижняя граница установлена ​​Option Base.
  • ReDim MyArr(5) нижняя граница установлена ​​Option Base.
  • Private MyArr(3) нижняя граница установлена ​​Option Base.
  • Public MyArr(3) нижняя граница установлена ​​Option Base.
  • MyArr = Array(1,2,3) Если записано как VBA.Array, функция Array возвращает массив с нижней границей, установленной Option Base модуля.

Код не чувствителен к изменениям Option Base:

  • Dim MyArr(1 To 3) нижняя граница равна 1.
  • ReDim MyArr(0 To 5) нижняя граница равна 0.
  • Private MyArr(0 To 5) нижняя граница равна 0.
  • Public MyArr(0 To 5) нижняя граница равна 0.
  • MyArr = VBA.Array(1,2,3) нижняя граница равна 0.
  • MyArr = Split("1,2,3",",") нижняя граница равна 0.
  • MyArr = VBA.Split("1,2,3",",") нижняя граница равна 0. Таким образом, в отличие от Array, поведение Split одинаково, независимо от того, префикс VBA. или нет. Всегда возвращает массив с нижней границей ноль.

Следующие утверждения верны независимо от Option Base модуля:

  • Индексирование в коллекцию Range.Cells начинается с 1.
  • Свойство .Value и .Value2 Range (с более чем одной ячейкой) представляет собой двумерный массив Variant(), нижние границы которого равны 1.

Я не думаю, что есть другие "проблемы", о которых нужно беспокоиться, но я хотел бы знать, есть ли.

0 голосов
/ 22 мая 2019

Опция Base не влияет на подсчет строк

Обратите внимание, что Option Base не влияет на подсчет строк и, следовательно, не влияет на массивы, которые были заполнены из значений диапазона, таких как

Dim MyArr() As Variant
MyArr = Range("A1:A10").Value

всегда приводить к массиву MyArr(1 To 10) независимо от того, Option Base равен 1 или 0.

Следить за функциями, которые возвращают массивы

Вам также может понадобиться следить за тем, возвращает ли функция массив, созданный с помощью Array() или без явных нижних границ.В этом случае вам также необходимо проверить обработку массива родительских функций / процедур, что может быть не так очевидно.

Это особенно сложно, если в разных модулях использовались разные Option Base.

Option Base 1 'if you plan to change this to 0 

Function MyArrayReturningFunction() As Variant
    MyArrayReturningFunction = Array(1, 2, 3)
End Function


'in another module

Option Base 0 'this was already 0 
              'so you might assume no changes are needed in this module BUT WRONG!

Sub ParentProcedure()
    Dim MyArr As Variant
    MyArr = MyArrayReturningFunction

    Dim iItem As Long
    For iItem = 1 To 3 'You need to take care here even if this module was already Base 0 
                       'because the array was recieved from a Base 1 function.
                       'Especially in combination with cells (see next paragraph)
        Debug.Print MyArr(iItem)
    Next iItem
End Sub

Нумерация массивов и нумерация строк

Также, если для циклического массива использовались циклы в комбинации с ячейками и диапазонами, вам необходимо обратить особое внимание на счетчики.

Option Base 1

Sub Test()
    Dim MyArr() As Variant
    MyArr = Array(1, 2, 3, 4, 5) 'MyArr(1 To 5)

    Dim iRow As Long
    For iRow = LBound(MyArr) To UBound(MyArr) 'It looks like safe to change because 
                                              'LBound/UBound is used BUT see below …
        Cells(iRow, A) = MyArr(iRow)
    Next iRow
End Sub

Необходимо изменить на

Option Base 0

Sub Test()
    Dim MyArr() As Variant
    MyArr = Array(1, 2, 3, 4, 5) 'MyArr(0 To 4)

    Dim iRow As Long
    For iRow = LBound(MyArr) To UBound(MyArr) 'even if LBound/UBound is already used,
        Cells(iRow + 1, A) = MyArr(iRow)      'the counter for the cells needs to be changed,
                                              'but NOT for the MyArr
    Next iRow
End Sub

Заключение

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

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