【问题标题】:VBA - Returning array from Property GetVBA - 从属性获取返回数组
【发布时间】:2011-08-02 13:59:44
【问题描述】:

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

'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

【问题讨论】:

    标签: arrays class vba return-value byref


    【解决方案1】:

    您没有 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  
    

    【讨论】:

    • 这是一个比公认的答案更有用的答案。谢谢:)
    • Get 属性旨在访问数组的特定元素,但是如果我们还想获得类似 Ubound(c.Vec) 的东西来进行循环呢?提前致谢
    【解决方案2】:

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

    一些替代方案是......

    • 使用 VBA.Collection 而不是数组。
    • 创建您自己的类来封装数组并公开用于间接访问和操作内部数组的过程。

    【讨论】:

    • 我认为这是正确的。它与我观察到的相符。不过,我希望这些事情得到更好的记录。您是否有一个很好的来源(超越经验)来说明此类内容?
    • Chip Person,一位 Excel 顾问和 MVP,在他的网站上说“数组总是通过引用传递”cpearson.com/excel/byrefbyval.aspx 他弄错了吗?
    • 他的网站确实不错。不过,我的意思是更多的“官方”资源——即帮助、VB 的旧 MS 手册等。这让我抓狂的是,像“分配 = 副本数组”这样的基本内容留给 MVP 提供,或者让用户提供通过实验发现。
    • “数组总是通过引用传递”的关键词是“通过”,意思是“参数”。过程调用返回的值不是参数。使用= 将数组分配给变量时,也没有传递参数。
    • @ThomasMcLeod VBA 规范确认数组在赋值时是浅拷贝的,除了数组内的对象和类实例,请参阅msdn.microsoft.com/en-us/library/ee157009(prot.20).aspx
    【解决方案3】:

    我想建议另一种使用 Collectionstatic 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
    

    将其转换为数组或将其实现为数组是直截了当的,但集合对我来说似乎更有用,缺点是它们的元素没有被隐式类型/(编译时)类型检查。
    所以这将是例如把它变成一个(只读)数组(在其他答案/cmets中提到了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 Ss answer 转换为使用某个数组的静态、可修改的模块属性,它将是:

    '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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-03-26
      • 2023-01-30
      • 2020-03-09
      • 1970-01-01
      • 1970-01-01
      • 2018-03-16
      • 2021-10-16
      相关资源
      最近更新 更多