是否有任何方法可以强制执行向集合中添加对象的类型?
据我所知,没有内置的方法来实现这一点。那么解决方案是将此集合设置为私有,并为通常可访问集合的方法(即Add、Remove、Item和Count)构建包装器函数吗?
我有点讨厌必须编写3个包装器函数,这些函数没有添加任何功能,只是为了能够将某些类型强制加入到Add方法中。但如果这是唯一的方法,那就只能这样做了。
无法避免包装器函数。这只是VBA使用的“通过包含/委托进行专业化”的模型固有的。
不过,您可以构建“自定义集合类”。您甚至可以使用For...Each
使它可迭代,但这需要离开VBA IDE并直接编辑源文件。
首先,请参阅旧版Visual Basic 6.0程序员指南中的“创建自己的集合类”部分:
http://msdn.microsoft.com/en-us/library/aa262340(v=VS.60).aspx
这里在stackoverflow上也有一个解答,描述了相同的事情:
vb6 equivalent to list<someclass>
然而,这些都是针对VB6编写的,而不是VBA。在VBA中,你无法在IDE中执行“procedure attributes”部分。你必须将类模块导出为文本,并使用文本编辑器添加它。Dick Kusleika的网站Daily Dose of Excel(Dick是一个常规的stackoverflow贡献者,你可能知道)有一篇来自Rob van Gelder的文章,展示了如何做到这一点:
http://www.dailydoseofexcel.com/archives/2010/07/04/custom-collection-class/
在你的情况下,为每个“自定义集合”类创建自己的模块可能不值得这么麻烦。(如果你只需要一次使用,并且它被埋在另一个类中,你可能会发现你并不希望暴露Collection
的所有功能。)People
)的“自定义集合类”呢?这太烦人了。
相反,我将这个想法泛化,并创建了一个名为UniformCollection
的新类,它可以包含任何数据类型——只要在UniformCollection
的任何给定实例中所有项目都是相同类型的。
我添加了一个私有变体,它是给定UniformCollection
实例可以包含的数据类型的占位符。
Private mvarPrototype As Variant
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
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
其余内容和示例基本相同(加上一些错误处理)。遗憾的是RvG没有走到底!更糟糕的是,微软没有将这种功能作为内置功能包含在内...
Collection
接口(https://dev59.com/km025IYBdhLWcg3w4Z-u)。 - jtolle我几乎做了与Jean-François Corbett相同的代码,但是由于某种原因没有起作用,因此我进行了适应性调整。
Option Explicit
Public pParametro As String
Private pColecao As New Collection
Public Sub Inicializar(ByVal parametro As String)
pParametro = parametro
End Sub
Public Sub Add(NewItem As Object)
If TypeName(NewItem) <> pParametro Then
MsgBox "Classe do objeto não é compatível à coleção"
Else
pColecao.Add NewItem
End If
End Sub
Public Property Get Count() As Long
Count = pColecao.Count
End Property
Public Property Get Item(NameOrNumber As Variant) As Variant
Set Item = pColecao(NameOrNumber)
End Property
Sub Remove(NameOrNumber As Variant)
pColecao.Remove NameOrNumber
End Sub
Set pFornecedores = New CCollection
pFornecedores.Inicializar ("CEmpresa")
CEmpresa是我想要的对象的类类型
CustomCollection.cls
类,从现在开始使用它来代替Collection
吗?无论如何,好答案,+1。 - Jean-François Corbett