限制类模块中Collection的类型

Jea*_*ett 5 collections vba types

我在类模块中有一个集合.我想限制对此集合"可添加"的对象类型,即集合应该只接受一个给定类型的对象而不是其他任何东西.

有没有办法强制添加到集合中的对象类型?

据我所知,没有内置的方法来做到这一点.是溶液,然后让这个私人收藏,并建立包装函数的方法通常是集合访问,即Add,Remove,Item,和Count

我有点讨厌必须编写3个不添加任何功能的包装函数,只是为了能够在Add方法中添加一些类型强制执行.但如果这是唯一的方法,那么这是唯一的方法.

jto*_*lle 5

没有办法避免包装函数.这只是VBA使用的"通过遏制/授权专业化"模式所固有的.

但是,您可以构建"自定义集合类".您甚至可以使用它进行迭代For...Each,但这需要离开VBA IDE并直接编辑源文件.

首先,请参阅旧的Visual Basic 6.0程序员指南的"创建自己的集合类"部分:

http://msdn.microsoft.com/en-us/library/aa262340(v=VS.60).aspx

这里还有一个关于stackoverflow的答案,它描述了同样的事情:

vb6相当于list <someclass>

但是,这些是为VB6而不是VBA编写的.在VBA中,您无法在IDE中执行"过程属性"部分.您必须将类模块导出为文本并使用文本编辑器将其添加.Dick Kusleika的网站Daily Dose of Excel(Dick是你可能知道的常规stackoverflow贡献者)有一篇来自Rob van Gelder的文章,展示了如何做到这一点:

http://www.dailydoseofexcel.com/archives/2010/07/04/custom-collection-class/

在你的情况下,遇到所有麻烦 - 每个"自定义集合"类都需要自己的模块 - 可能不值得.(如果你只有一个用途,它被埋在另一个类中,你可能会发现你不想公开所有的功能Collection.)


Jea*_*ett 3

这就是我所做的。我喜欢 Rob van Gelder 的示例,正​​如 @jtolle 所指出的,但为什么我应该满足于制作一个People永远只接受一种特定对象类型(例如)的“自定义集合类”?正如@jtolle 指出的,这非常烦人。

相反,我概括了这个想法并创建了一个名为 的新类UniformCollection,它可以包含任何数据类型——只要在任何给定的UniformCollection.

我添加了一个私有变体,它是给定实例可以包含的数据类型的占位符UniformCollection

Private mvarPrototype As Variant
Run Code Online (Sandbox Code Playgroud)

在创建实例之后UniformCollection和使用它之前,必须通过指定它将包含哪种数据类型来初始化它。

Public Sub Initialize(Prototype As Variant)
    If VarType(Prototype) = vbEmpty Or VarType(Prototype) = vbNull Then
        Err.Raise Number:=ERR__CANT_INITIALIZE, _
            Source:=TypeName(Me), _
            Description:=ErrorDescription(ERR__CANT_INITIALIZE) & _
                TypeName(Prototype)
    End If
    ' Clear anything already in collection.
    Set mUniformCollection = New Collection
    If VarType(Prototype) = vbObject Or VarType(Prototype) = vbDataObject Then
        ' It's an object. Need Set.
        Set mvarPrototype = Prototype
    Else
        ' It's not an object.
        mvarPrototype = Prototype
    End If
    ' Collection will now accept only items of same type as Prototype.
End Sub
Run Code Online (Sandbox Code Playgroud)

然后,Add 方法将只接受与 Prototype 类型相同的新项(无论是对象还是原始变量......尚未使用 UDT 进行测试)。

Public Sub Add(NewItem As Variant)
    If VarType(mvarPrototype) = vbEmpty Then
        Err.Raise Number:=ERR__NOT_INITIALIZED, _
            Source:=TypeName(Me), _
            Description:=ErrorDescription(ERR__NOT_INITIALIZED)
    ElseIf Not TypeName(NewItem) = TypeName(mvarPrototype) Then
        Err.Raise Number:=ERR__INVALID_TYPE, _
            Source:=TypeName(Me), _
            Description:=ErrorDescription(ERR__INVALID_TYPE) & _
                TypeName(mvarPrototype) & "."
    Else
        ' Object is of correct type. Accept it.
        ' Do nothing.
    End If

    mUniformCollection.Add NewItem

End Sub
Run Code Online (Sandbox Code Playgroud)

其余部分与示例中几乎相同(加上一些错误处理)。可惜RvG没能走完全程!更糟糕的是微软没有将这种东西作为内置功能包含在内......