VBA Array函数将简单类型的变量转换为值,不存储变量引用

Ale*_*nov 2 arrays collections vba

VBA Array 函数将简单类型的变量转换为值,不存储变量引用。但是如果我传递一个类变量,它会按预期工作。它应该是这样的还是我错过了什么?

主模块

Sub test()

Dim collection As collection
Set collection = New collection

Dim i As Long
Dim cl As New tst

i = 25
cl.i = 25

Debug.Print "Original i = " & i
Debug.Print "Original cl.i = " & cl.i
Debug.Print

collection.Add Item:=Array(i)
collection.Add Item:=Array(cl)

Debug.Print "i in array in collection: collection(1)(0) = " & collection(1)(0)
Debug.Print "i from class in array in collection: collection(2)(0).i = " & collection(2)(0).i
Debug.Print

i = i + 1
cl.i = cl.i + 1

Debug.Print "Adding: i = i + 1"
Debug.Print

Debug.Print "Original i = " & i ' 26
Debug.Print "Original cl.i = " & cl.i '26
Debug.Print

Debug.Print "i in array in collection: collection(1)(0) = " & collection(1)(0) '25, but I expect 26
Debug.Print "i from class in array in collection: collection(2)(0).i = " & collection(2)(0).i '26 correct
Debug.Print

End Sub
Run Code Online (Sandbox Code Playgroud)

类测试

Public i As Long
Run Code Online (Sandbox Code Playgroud)

输出

Original i = 25
Original cl.i = 25

i in array in collection: collection(1)(0) = 25
i from class in array in collection: collection(2)(0).i = 25

Adding: i = i + 1

Original i = 26
Original cl.i = 26

i in array in collection: collection(1)(0) = 25
i from class in array in collection: collection(2)(0).i = 26
Run Code Online (Sandbox Code Playgroud)

Mat*_*don 5

是不是应该是这样

确实。无论您是传递值还是对象引用,行为都是完全相同的。

当您添加i到集合,副本ByVal中)i被添加到集合; 递增i不会递增副本。

当您添加cl到集合中时,指向该对象的指针的副本(也)被添加到集合中;修改该指针也不会修改集合中的副本:ByVal

Public Sub test()
    Dim c As Collection
    Set c = New Collection
    Dim o As Class1
    Set o = New Class1
    Debug.Print VarPtr(o), ObjPtr(o)
    c.Add o
    Debug.Print VarPtr(c(1)), ObjPtr(c(1))
End Sub
Run Code Online (Sandbox Code Playgroud)

此代码输出如下内容:

 725937672     221317072 
 725937528     221317072 
Run Code Online (Sandbox Code Playgroud)

请注意,这两个指针不同,但都指向同一个对象引用。

如果我们在本地影响该对象指针的本地副本......

Debug.Print VarPtr(o), ObjPtr(o)
c.Add o
Set o = Nothing
Debug.Print VarPtr(c(1)), ObjPtr(c(1))
Debug.Print VarPtr(o), ObjPtr(o)
Run Code Online (Sandbox Code Playgroud)

现在的输出如下:

 725937672     221317072 
 725937528     221317072 
 725937672     0 
Run Code Online (Sandbox Code Playgroud)

我们重新分配oNothing,但集合c 仍然有对对象的引用!我们根本没有影响对象!

Public i您的测试类的成员从未被复制到任何地方,集合甚至不知道/关心它:所有集合都知道,它持有对对象的引用。

因此,当您这样做时cl.i = 26,您并没有分配集合知道的任何内容。您只是说“获取地址 X 处的对象(与ObjPtr集合中保存的对象相同!),获取其i属性,并为其分配值 26”:该集合的指针副本从未更新。

当你这样做时i = 26,你也没有分配集合知道的任何东西。您是说“获取地址 X 处的变量(局部变量),将其赋值为 26”:该值的集合副本从未更新。