使用数组初始化VBA对象

4

我正在尝试创建一个包含数组的类,并且在为其创建类时遇到了问题...

类:

Private pST(0 To 2) As String

Public Property Get ST() As String
   ST() = pST()
End Property
Public Property Let ST(value() As String)  '<---- ERROR HERE
   pST() = value()
End Property

代码运行:

Sub test()

   Dim foo As cPurchaseOrder
   Set foo = New cPurchaseOrder

   foo.ST(0) = "test"

   Debug.Print foo.ST(0)

End Sub

错误信息:

编译错误:

相同属性的属性过程定义不一致,或者属性过程具有可选参数、ParamArray 或无效的 Set 最终参数。

问题描述:

如何正确初始化包含数组变量的类?

编辑:关于 Mat's Mug 的回答

类已更改:

Private pST As Variant

Public Property Get STContent(ByVal index As Long) As String
    STContent = pST(index)
End Property

Public Property Let STContent(ByVal index As Long, ByVal value As String)
    pST(index) = value
End Property

Private Sub Class_Initialize()
   ReDim pST(0 To 2)
End Sub

代码运行测试:

Sub test()

   Dim foo As cPurchaseOrder
   Set foo = New cPurchaseOrder

   foo.STContent(0) = "test" '<--- Type mismatch here

   Debug.Print foo.STContent(0)

End Sub

你需要在 Class_Initialize 处理程序中初始化数组,例如 ReDim pST(0 To 20),然后才能开始对其进行赋值。如果支持字段是编译时数组,则错误将为“索引超出范围”。 - Mathieu Guindon
@Mat'sMug 我已经添加了 Class_Initialize,当我只给 foo.STContent(0) 赋值时它可以正常工作。但是当我尝试输出该值时,在 Public Property Get STContent 中的 Content = pST(index) 上没有得到 变量未定义 的错误提示。 - Maldred
抱歉如果我有点烦人,我对于Class对象还很陌生,还在学习中:( - Maldred
在你的模块顶部加上 Option Explicit,避免从互联网上随意复制粘贴代码 ;-) 该赋值语句为 STContent = pST(index) - Mathieu Guindon
哦,这样就行了...不确定我怎么会错过那个,抱歉! - Maldred
现在完美运行!谢谢 :) - Maldred
3个回答

6
您的getter需要返回一个String()数组,以保持类型的一致性:
Public Property Get ST() As String()

然而,我不建议像这样公开数组。首先,因为指定类型的数组相当麻烦,其次,setter (Property Let) 在这里实际上是作弊:

Public Property Let ST([ByRef] value() As String)

除非你显式指定ByVal,否则在VBA中参数始终是以ByRef方式传递的...除了Property Let有一个怪异之处——RHS/值参数总是在运行时以ByVal方式传递。
并且数组只能通过ByRef传递。
因此,获取(或分配)整个数组的属性没有太多意义。
更好的方法是通过封装数组(我会将其作为Variant),并通过索引属性公开其内容(而不是数组本身)。
Private internal As Variant 'String array

'...

Public Property Get Content(ByVal index As Long) As String
    Content = internal(index)
End Property

Public Property Let Content(ByVal index As Long, ByVal value As String)
    internal(index) = value
End Property

我非常喜欢你的方法,解释得非常好!然而,我在使用这个方法时遇到了另一个问题。我运行了代码 foo.Content(0) = "test",但是收到了“类型不匹配”的错误提示。 - Maldred
你的解释中“欺骗”setter有什么问题吗? - Maldred
不确定那个类型不匹配的问题,可能与你的后备字段有关,你把它变成了变体吗?它被初始化了吗?至于“作弊”,在我看来,公开数组设置器只会引发问题...更不用说这违背了类/对象的目的,即封装数据。 - Mathieu Guindon
我已经编辑了我的问题,与您的答案和我在评论中提出的新问题相关。 - Maldred
@Maldred,除非你显示地初始化了数组,否则它只是一个“Variant/Empty”,直到你这样做。 - Mathieu Guindon
你可以在 Class_Initialize 处理程序中完成这个操作。 - Mathieu Guindon

2

你有很多问题。

首先,你的Property Get需要返回一个字符串数组。其次,你的数组需要是动态的,否则你需要重写整个东西来传递索引值,否则没有办法指示你正在传递哪个值到数组中。因此,例如使用动态数组:

Private pST() As String

Public Property Get ST() As String()
   ST = pST
End Property
Public Property Let ST(value() As String)
   pST() = value()
End Property

以及调用代码:

Sub test()

   Dim foo As cPurchaseOrder
   Set foo = New cPurchaseOrder
   Dim asData() As String
   ReDim asData(0)
   asData(0) = "test"

   foo.ST = asData

   Debug.Print foo.ST()(0)

End Sub

很遗憾,我无法确定原意。

0

这里已经很晚了,但还是试一试。在这个模块中:

Option Explicit

Sub Test()

   Dim foo As cPurchaseOrder
   Set foo = New cPurchaseOrder
   foo.AddValueToSt "test", 1
   Debug.Print foo.ST(1)

End Sub

在这个类中:
Option Explicit

Private pST

Public Property Get ST() As Variant
   ST = pST
End Property

Public Property Let ST(value As Variant)
   pST = value
End Property

Public Function AddValueToSt(value As Variant, position As Long)
    pST(position) = value
End Function

Private Sub Class_Initialize()
    ReDim pST(2)
End Sub

这是我使用工厂方法模式的方式。当我说“我的方式”时,对我来说,这种模式被翻译为“每当某个OOP需要超过5分钟的思考时,只需添加一个函数。”


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接