类模块类型数组未更新

时间:2017-06-13 17:23:56

标签: arrays excel vba excel-vba vb6

我已经击中了一些奇怪的数组,我可以为整个数组分配值,但不是单个数组成员。

这是一个名为Class_E

的数据类模块
Sub main()
    Dim r As Class_E
    Set r = Band()
End Sub

Function Band() As Class_E
    Set Band = New Class_E

    'Part 1: Initialize the variables
    Debug.Print "Part 1"
    Band.Name = Array("Edison", "Tesla", "Faraday", "Turing")
    Debug.Print "Before: Name={" & Band.Name(0) & ", " & Band.Name(1) & ", " & Band.Name(2) & ", " & Band.Name(3) & "}"
    Band.Age = Array(10, 10, 10, 10)
    Debug.Print "Before: Age={" & Band.Age(0) & ", " & Band.Age(1) & ", " & Band.Age(2) & ", " & Band.Age(3) & "}"

    'Part 2: Change values of arrays, by item
    Debug.Print "Part 2"
    For k = LBound(Band.Name) To UBound(Band.Name)
        Debug.Print "k=" & k
        Band.Name(k) = "Foo"
        Band.Age(k) = 999
    Next k
    Debug.Print "After: Name={" & Band.Name(0) & ", " & Band.Name(1) & ", " & Band.Name(2) & ", " & Band.Name(3) & "}"
    Debug.Print "After: Age={" & Band.Age(0) & " " & Band.Age(1) & " " & Band.Age(2) & " " & Band.Age(3) & "}"

    'Part 3: Change values of array, entirely
    Debug.Print "Part 3"
    Band.Name = Array("Spring", "Summer", "Autumn", "Winter")
    Debug.Print "Again: Name={" & Band.Name(0) & ", " & Band.Name(1) & ", " & Band.Name(2) & ", " & Band.Name(3) & "}"
    Band.Age = Array(11, 11, 11, 11)
    Debug.Print "Again: Age={" & Band.Age(0) & ", " & Band.Age(1) & ", " & Band.Age(2) & ", " & Band.Age(3) & "}"

    'Part 4: Use another temp array variable
    Debug.Print "Part 4"
    Dim Temp_Name As Variant, Temp_Age As Variant
    Temp_Name = Band.Name
    Temp_Age = Band.Age
    For k = LBound(Band.Name) To UBound(Band.Name)
        Debug.Print "k=" & k
        Temp_Name(k) = "Foo"
        Temp_Age(k) = 999
    Next k
    Debug.Print "Temp: Name={" & Temp_Name(0) & ", " & Temp_Name(1) & ", " & Temp_Name(2) & ", " & Temp_Name(3) & "}"
    Debug.Print "Temp: Age={" & Temp_Age(0) & " " & Temp_Age(1) & " " & Temp_Age(2) & " " & Temp_Age(3) & "}"

    'Part 5: Original arrays again
    Debug.Print "Part 5"
    Debug.Print "Again: Name={" & Band.Name(0) & ", " & Band.Name(1) & ", " & Band.Name(2) & ", " & Band.Name(3) & "}"
    Debug.Print "Again: Age={" & Band.Age(0) & ", " & Band.Age(1) & ", " & Band.Age(2) & ", " & Band.Age(3) & "}"

End Function

这是正文代码,只是为2个数组分配和重新分配值

Part 1
Before: Name={Edison, Tesla, Faraday, Turing}
Before: Age={10, 10, 10, 10}
Part 2
k=0
k=1
k=2
k=3
After: Name={Edison, Tesla, Faraday, Turing}
After: Age={10 10 10 10}
Part 3
Again: Name={Spring, Summer, Autumn, Winter}
Again: Age={11, 11, 11, 11}
Part 4
k=0
k=1
k=2
k=3
Temp: Name={Foo, Foo, Foo, Foo}
Temp: Age={999 999 999 999}
Part 5
Again: Name={Spring, Summer, Autumn, Winter}
Again: Age={11, 11, 11, 11}

这是我的输出屏幕

{{1}}

问题:

1.为什么第2部分中的简单赋值没有执行?并且没有错误消息。我们没有问题重新分配数组,如第3部分所示。

2.为什么第4部分中的“Temp_Name = Band.Name”是数组值的副本而不是数组指针?没有关于临时阵列的内存分配的指令。

非常感谢您的投入。

2 个答案:

答案 0 :(得分:3)

使用数组作为公共类成员是有问题的。 VBA不允许这样做的原因。您试图通过将成员声明为Variant来克服此限制,但这并不能解决问题。

您可以使用CollectionDictionary,因为它们是Objects,因此您可以Set 引用。但是VBA数组是值类型。因此,当您从函数中获取数组时,您将获得该数组的副本

  
      
  1. 为什么第2部分中的简单分配没有执行?并且没有错误消息。我们没有问题重新分配数组,如第3部分所示。
  2.   

因为您实际上处理了数组的副本。在声明中

Band.Name(k) = "Foo"

虽然Band.Name似乎直接访问该类的一个字段,但它实际上是通过属性get“wrapper”访问它;对于公共类成员,情况总是如此,编译器会自动添加COM的IDispatch接口所需的get / let包装器以及最终的后期绑定(在object引用中访问类)。包装器返回数组的副本不是引用,因为如前所述,VBA中的数组(以及字符串)是 value-types < / em>,而不是对象。所以yoiu处理了阵列的副本。

您可以通过添加在成员数组中分配条目的Property Let方法来解决此问题。请考虑为您的班级编写此代码:

Public Names As Variant '<-- Change to plural to add property get/let
Public Ages As Variant  ' <-- Same

Public Property Let Name(i As Long, s As String)
  Names(i) = s
End Property

Public Property Let Age(i As Long, val As Long)
  Ages(i) = val
End Property

您可以使用这些来分配成员数组中的条目。然后,您的Part2将按预期工作。

  
      
  1. 为什么第4部分中的“Temp_Name = Band.Name”是数组值的副本而不是数组指针?没有关于临时阵列的内存分配的指令。
  2.   

如前所述,数组是值类型,而不是对象。将数组分配给变量始终会创建副本,而不是像对象案例那样创建重复引用。 (添加到包装器属性get,你发现自己距离初始类的数组两英里)。

答案 1 :(得分:1)

根据我的建议来翻转你如何将数组从Band.Name(0到3)存储到Band(0到3).Name,这里有一些工作代码。

Class_E(代码)类模块代码表

Option Explicit

Private pName As String
Private pAge As Long

Public Property Get Name() As String
    Name = pName
End Property
Public Property Let Name(Value As String)
    pName = Value
End Property

Public Property Get Age() As Long
    Age = pAge
End Property
Public Property Let Age(Value As Long)
    pAge = Value
End Property

标准模块1(代码)代码表

Option Explicit

Sub main()
    Dim i As Long, r() As New Class_E
    r = fillBand()
    For i = LBound(r) To UBound(r)
        Debug.Print r(i).Name & " - " & r(i).Age
    Next i
End Sub

Function fillBand() As Class_E()
    Dim tmpBands() As New Class_E, tmp1 As Variant, tmp2 As Variant, i As Long

    'Part 1: Initialize the variables
    Debug.Print "Part 1"
    tmp1 = Array("Edison", "Tesla", "Faraday", "Turing")
    tmp2 = Array(5, 10, 15, 20)
    ReDim tmpBands(LBound(tmp1) To UBound(tmp1))

    For i = LBound(tmp1) To UBound(tmp1)
        With tmpBands(i)
            .Name = tmp1(i)
            .Age = tmp2(i)
        End With
    Next i

    Debug.Print "Before: Name={" & tmpBands(0).Name & ", " & tmpBands(1).Name & ", " & tmpBands(2).Name & ", " & tmpBands(3).Name & "}"
    Debug.Print "Before: Age={" & tmpBands(0).Age & ", " & tmpBands(1).Age & ", " & tmpBands(2).Age & ", " & tmpBands(3).Age & "}"

    'Part 2: Initialize the variables
    Debug.Print "Part 2"
    tmp1 = Array("foo", "bar", "foobar", "else")
    tmp2 = Array(9, 99, 999, 9999)
    ReDim tmpBands(LBound(tmp1) To UBound(tmp1))

    For i = LBound(tmp1) To UBound(tmp1)
        tmpBands(i).Name = tmp1(i)
        tmpBands(i).Age = tmp2(i)
    Next i

    Debug.Print "Before: Name={" & tmpBands(0).Name & ", " & tmpBands(1).Name & ", " & tmpBands(2).Name & ", " & tmpBands(3).Name & "}"
    Debug.Print "Before: Age={" & tmpBands(0).Age & ", " & tmpBands(1).Age & ", " & tmpBands(2).Age & ", " & tmpBands(3).Age & "}"

    'Part 3: Initialize the variables
    Debug.Print "Part 3"
    tmp1 = Array("spring", "summer", "fall", "winter")
    tmp2 = Array(1, 11, 111, 1111)
    ReDim tmpBands(LBound(tmp1) To UBound(tmp1))

    For i = LBound(tmp1) To UBound(tmp1)
        tmpBands(i).Name = tmp1(i)
        tmpBands(i).Age = tmp2(i)
    Next i

    Debug.Print "Before: Name={" & tmpBands(0).Name & ", " & tmpBands(1).Name & ", " & tmpBands(2).Name & ", " & tmpBands(3).Name & "}"
    Debug.Print "Before: Age={" & tmpBands(0).Age & ", " & tmpBands(1).Age & ", " & tmpBands(2).Age & ", " & tmpBands(3).Age & "}"

    fillBand = tmpBands
End Function

立即窗口的结果

Part 1
Before: Name={Edison, Tesla, Faraday, Turing}
Before: Age={5, 10, 15, 20}
Part 2
Before: Name={foo, bar, foobar, else}
Before: Age={9, 99, 999, 9999}
Part 3
Before: Name={spring, summer, fall, winter}
Before: Age={1, 11, 111, 1111}
Returned Values:
spring - 1
summer - 11
fall - 111
winter - 1111