Назначить объект в массив в пределах al oop в VBA - PullRequest
2 голосов
/ 19 марта 2020

Я пытаюсь заполнить массив объектами, созданными в al oop, следующим образом. Проблема в том, что все ячейки, похоже, имеют один и тот же объект в конце. Объяснение может быть таким, что obj не является локальной переменной по отношению к l oop.

Sub foo()
    Dim Arr(1 To 3) As Class1
    Dim i As Integer
    For i = 1 To 3
        Dim obj As New Class1
        obj.name = i
        Set Arr(i) = obj
    Next
    For i = 1 To 3
        Debug.Print Arr(i).name 
    Next
End Sub

Удивительно, но на выходе получается

3
3
3

Я также пытался удалите Set и вместо этого Arr(i) = obj. Это приводит к Object variable or with block variable not set.

Ответы [ 4 ]

3 голосов
/ 19 марта 2020

Ваша проблема - объявление вашего объекта.

Dim foo as New bar

Это называется самозаверяющим объявлением , что делает установку нового объекта необязательной. Если вы вызываете член объекта и он еще не установлен, он создается (неявный Set foo = New bar). Но, как вы уже создали экземпляр (при первом вызове obj.name). этот используется повторно, и одна и та же ссылка сохраняется три раза для одного и того же объекта-экземпляра. Вот почему все элементы в массиве возвращают одно и то же значение, поскольку они являются одним и тем же объектом-экземпляром, а не тремя разными.

Так что не используйте New в объявлениях, тогда вам всегда нужны Set foo и можете проверить экземпляр объекта на Nothing.

Вторая проблема с вашим кодом заключается в том, что назначение объекта массиву состоит в том, что удаление элементов из массива подвержено ошибкам, а не удаленные ссылки приводят к не уничтожению, а неиспользуемые объекты.

Предпочтительным хранилищем для объекта (-references) является Collection.

Sub foo()
    Dim ObjCollection as Collection
    Set ObjCollection = New Collection
    Dim i As Integer
    For i = 1 To 3
        Dim obj As bar
        Set obj = New bar
        obj.name = i
        ObjCollection.Add obj
    Next
    For i = 1 To 3
        Debug.Print ObjCollection(i).name 
    Next
End Sub
2 голосов
/ 19 марта 2020

У вас есть 2 способа сделать это:

Примечания : obj не был воссоздан, поэтому при следующем вызове obj в Arr (1) по-прежнему действует последующий вызов.

Первый:

Sub foo()
    Dim Arr(2) As Variant

    Dim i As Integer
    Dim obj As New Class1
    For i = 0 To 2
        Set obj = New Class1 '<<<-----
        obj.name = i
        Set Arr(i) = obj
    Next
    For i = 0 To 2
        Debug.Print Arr(i).name
    Next
End Sub

Второй:

Sub foo()
    Dim Arr(2) As Variant
    Dim i As Integer
    For i = 0 To 2
        Dim obj As New Class1
        obj.name = i
        Set Arr(i) = obj
        Set obj = Nothing  <<<-----
    Next
    For i = 0 To 2
        Debug.Print Arr(i).name
    Next
End Sub
2 голосов
/ 19 марта 2020

Это путь: -

Sub foo()
    Dim Arr(1 To 3) As Variant
    Dim i As Integer

    For i = 1 To 3
        Set Arr(i) = Worksheets(i)
    Next
    For i = 1 To 3
        Debug.Print Arr(i).Name
    Next
End Sub
0 голосов
/ 19 марта 2020

Попробуйте, это избавит вас от многих головных болей. Ура!

Option Explicit

Sub foo()    
    Dim Arr(1 To 3) As New Class1 ' < good to know this version
    Dim i As Long
    For i = 1 To 3
       With Arr(i) ' < saves you some typing
          .Name = i
          Debug.Print .Name
       End With
    Next
End Sub
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...