VBA: Я изменяю arr (0), не могу понять, почему arr (1) изменяется? - PullRequest
1 голос
/ 30 марта 2012

У меня есть этот код:

Call MakeRoomForArrayItem(interAll, 0)

interAll(0).StartY = tempStartY
interAll(0).K = tempK

В первой строке я успешно создаю новый удлиненный метод interAll () по одному.

Тогда я ожидаю, что строки 2 и 3 будут влиять только на interAll (0), но они выполняют те же изменения для interAll (1). Почему это? Не удалось ли мне создать новый объект для interAll (1)?

Sub MakeRoomForArrayItem(ItemArray As Variant, ByVal ItemElement As Integer)
    Dim i As Integer
    ReDim Preserve ItemArray(LBound(ItemArray) To UBound(ItemArray) + 1)

    For i = UBound(ItemArray) - 1 To ItemElement Step -1
        Set ItemArray(i + 1) = ItemArray(i)
    Next
    'Erase values in object ItemArray(ItemElement) would be nice
End Sub

Я успешно использовал ту же функцию в других случаях. Может ли это быть связано с отсутствующими объявлениями в вызывающей функции?

РЕДАКТИРОВАТЬ: я исправил проблему, добавив

Set interval = New CInterval
Set interAll(0) = interval

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

Ответы [ 2 ]

1 голос
/ 30 марта 2012

Это зависит от того, какую переменную вы передаете в MakeRoomForArrayItem.Если ваш массив содержит переменную типа значения, такую ​​как Integer или Boolean, он будет работать, потому что оператор присваивания

Set ItemArray(i + 1) = ItemArray(i)

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

РЕДАКТИРОВАТЬ: Когда вы сделали вызов New CInterval, вы фактически присвоили новую переменную вместо копирования ссылки на предыдущую переменную.Вот почему ваше исправление сработало.Без вашего исправления у вас был только один «слот» в памяти для хранения значения, но ваш массив ссылался на эту память несколько раз.После исправления у вас было столько «слотов» в памяти, сколько было вызовов New CInterval, и каждый элемент массива ссылался на новую ячейку памяти.

Возможно, поможет следующий код:

Set interval1 = New CInterval   ' you have a single CInterval instance
Set interval2 = New CInterval   ' changes to interval1 or interval2 do not affect each other
Set interval3 = interval2       ' changes to interval3 also make changes to interval2,
                                ' because they are the same object.
Dim arr as CInterval(3)        
' Create a single array that has 3 elements, 
' which will hold 3 references to CInterval instances.  
' Those references may or may not be to the same actual CInterval instance.

Set arr(0) = interval1   ' the first element of the array references the first object instance
Set arr(1) = interval1   ' the second element of the array also references the first object instance
Set arr(2) = interval2   ' the third element of the array references the second object instance. 
                         ' Changes to this element will affect both interval2 and interval3, because they are references to the same object in memory.
1 голос
/ 30 марта 2012

Когда вы делаете это:

Set ItemArray(i + 1) = ItemArray(i)

Вы копируете ссылку, а не значение. Поэтому в конце цикла, когда i=0, эта строка говорит: «скопируйте ссылку на объект в ItemArray(0) в местоположение 1». Таким образом, и ItemArray(0), и ItemArray(1) содержат ссылки, указывающие на один и тот же экземпляр объекта. Вы должны быть в состоянии подтвердить это с помощью отладчика.

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