Доступ к коллекции вызывает ошибку подписки вне диапазона? - PullRequest
0 голосов
/ 14 марта 2019

У меня есть UserForm, который при неправильном вводе пользователем вызывает следующую процедуру, которая выделяет поле и отключает кнопку «сохранить изменения».

Private disabledElems As New Collection

Private Sub disable(ByRef controlName As String)
    UserForm1.Controls(controlName).BackColor = &H8080FF
    Me.save_button.Enabled = False
    Dim i As Byte

    If disabledElems.Count <> 0 Then
        For i = 1 To disabledElems.Count
            If disabledElems(i) = controlName Then
                Exit Sub ' we dont want to add duplicates to collection
            End If
        Next i
    End If

    disabledElems.Add controlName ' otherwise add to collection

End Sub

Если ввод исправлен, он вызывает процедуру enable, которая выглядит следующим образом:

Private Sub enable(ByRef controlName As String)
    Me.Controls(controlName).BackColor = &H80000005
    Dim i As Byte

    For i = 1 To disabledElems.Count
        If disabledElems(i) = controlName Then
            disabledElems.Remove i ' remove the enabled element upon match 
        End If
    Next i

    If disabledElems.Count = 0 Then
        save_button.Enabled = True
    End If


End Sub

Кажется, это работает очень хорошо, когда я пытаюсь это сделать с одним Textbox

enter image description here


Однако, как только у меня несколько неправильных записей , моя enable процедура, похоже, выдает Subscript out of range error вроде бы без причины.

Выделенная строка в отладчике:

If disabledElems(i) = controlName Then

enter image description here

Я могуне понимаю, что может быть причиной этого.Есть идеи?

enter image description here

1 Ответ

1 голос
/ 14 марта 2019

Ах, хорошо, это один из тех классических "при удалении строки, цикла от конца к началу "

По сути, причина, по которой Subscript out of range была выброшена - после удаления элемента из коллекции через

disabledElems.Remove i

Уменьшен размер Collection с Collection.Count до Collection.Count - 1, однако во время объявления цикла for i уже был жестко установлен по сравнению с предыдущим Collection.Count


В практическом примере:

Допустим, мой Collection выглядит так

 disabledElems = "button1", "button2"

После этого

controlName = "button1"
For i = 1 to disabledElems.Count ' <= 2
   If disabledElems(i) = controlName ' < True for i = 1
      disabledElems.Remove i ' < button1 was removed from collection, however it still loops
   End If
   ' will loop to i = 2. However disabledElems(2) no longer exists, because upon removal _
     the button2 was shifted to disabledElems(1) - hence Subscript out of range
Next i

Очевидный случай попытки получить доступ к элементу, который сместил свою позицию в очереди.


Есть два возможных исправления (о которых я могу думать) :

1. Принудительно Exit Sub при удалении

For i = 1 to disabledElems.Count
   If disabledElems(i) = controlName
       disabledElems.Remove i
       Exit Sub
   End If
Next i

2. Цикл от конца к началу

Dim i as Integer ' needs to be redeclared to int, because Byte can't -1
For i = disabledElems.Count to 1 Step -1
   If disabledElems(i) = controlName
      disabledElems.Remove i
   End If
Next i
...