16

如果数组是通过引用返回的,为什么以下不起作用:

'Class1 class module
Private v() As Double
Public Property Get Vec() As Double()
    Vec = v()
End Property
Private Sub Class_Initialize()
    ReDim v(0 To 3)
End Sub
' end class module

Sub Test1()
    Dim c As Class1
    Set c = New Class1
    Debug.Print c.Vec()(1) ' prints 0 as expected
    c.Vec()(1) = 5.6
    Debug.Print c.Vec()(1) ' still prints 0
End Sub
4

3 回答 3

34

你没有 let 属性。此外,get 属性返回整个数组,而不仅仅是有问题的元素。将 Property Get 的返回类型从 Double() 更改为纯 Double。添加属性让。请注意,它需要两个输入,但只有一个传递给它。最后一个变量(MyValue,在这种情况下)被假定为从 = 符号之后的任何内容中获取它的值。在 Test1() 早期的某个地方放置一个断点,然后在 Locals 窗口中查看这些值是如何受到影响的。比较原始代码和我的代码创建的变量:

'Class1 class module
Private v() As Double
Public Property Get Vec(index As Long) As Double
    Vec = v(index)
End Property
Public Property Let Vec(index As Long, MyValue As Double)
    v(index) = MyValue
End Property
Private Sub Class_Initialize()
    ReDim v(0 To 3)
End Sub
' end class module

'Begin module
Sub Test1()
    Dim c As Class1
    Set c = New Class1
    Debug.Print c.Vec(1) ' prints 0 as expected
    c.Vec(1) = 5.6
    Debug.Print c.Vec(1) ' prints 5.6
End Sub
'End module  
于 2013-05-31T19:19:44.277 回答
14

在 VBA 中,数组永远不会通过引用返回,除非它们通过ByRef参数返回。此外,每当您使用=将数组分配给变量时,即使您将其分配给过程内部的 ByRef 参数,您也已经制作了该数组的新副本,因此您几乎不走运尝试使这项工作。

一些替代方案是...

  • 使用 VBA.Collection 而不是数组。
  • 创建您自己的类来封装数组并公开用于间接访问和操作内部数组的过程。
于 2011-04-10T18:23:24.557 回答
0

我想建议另一种使用 aCollection和 astatic Property而无需使用的好方法:

想象一下,您希望将xlCVError枚举作为一个数组(或集合),例如在错误时循环遍历它并根据实际错误进行处理。

以下内容在访问时初始化一次:

'from https://stackoverflow.com/a/56646199/1915920
Static Property Get XlCVErrorColl() As Collection
    Dim c As Collection  'will be already initalized after 1st access
                         'because of "Static Property" above!
    Set XlCVErrorColl = c
    If Not c Is Nothing Then Exit Property

   'initialize once:

    Set c = New Collection
    c.Add XlCVError.xlErrDiv0
    c.Add XlCVError.xlErrNA
    c.Add XlCVError.xlErrName
    c.Add XlCVError.xlErrNull
    c.Add XlCVError.xlErrNum
    c.Add XlCVError.xlErrRef
    c.Add XlCVError.xlErrValue
    Set XlCVErrorColl = c
End Property

将其转换为数组或将其实现为数组是直截了当的,但集合对我来说似乎更有用,缺点是它们的元素没有被隐式类型/(编译时)类型检查。
因此,这会将它变成一个(只读)数组(在其他答案/评论中提到了 in-mem-copy-disadvantage):

'from https://stackoverflow.com/a/56646199/1915920
Static Property Get XlCVErrorArr() As XlCVError()
   Dim a() As XlCVError
   XlCVErrorArr = a
   If UBound( a ) > 0 Then Exit Property

   'initialize once:

   Dim c As Collection:  Set c = XlCVErrorColl
   ReDim a(c.Count)
   Dim i As Integer:  For i = 1 To c.Count 
       a(i) = c(i)
   Next i
   XlCVErrorArr = a
End Function

因此,使用某个数组将示例从Clayton S的答案转换为静态的、可修改的模块属性,它将是:

'module (no class required)
'from https://stackoverflow.com/a/56646199/1915920

Private v() As Double

Static Property Get Vec(index As Long) As Double
    If UBound(v) < 3 Then  'initialize once:
      ReDim v(0 To 3)  'one could initialize it with anyting after here too
    end if

    Vec = v(index)
End Property

Public Property Let Vec(index As Long, MyValue As Double)
    v(index) = MyValue
End Property
于 2019-06-18T09:43:34.613 回答