VBA:是不是可以创建一个行为类似于集合的类模块?

Posted

技术标签:

【中文标题】VBA:是不是可以创建一个行为类似于集合的类模块?【英文标题】:VBA: Is possible to create a class module which behave like a Collection?VBA:是否可以创建一个行为类似于集合的类模块? 【发布时间】:2020-12-08 14:35:13 【问题描述】:

我想知道是否可以创建我自己的类,它的行为就像一个集合。最好在示例中显示:

我目前的知识:

类模块MyClass

Public oCollection As Collection
Public OtherData as Long
... 'Another Variables, Properties, Functions and Subs

模块

...
For Each oItem In MyClass.oCollection 'I need to address Collection inside the object
  If oItem.OtherData = 0 Then
...

我想要达到的目标:

...
For Each oItem In MyClass 'Want to be able to iterate over oCollection just from Class
  If oItem.OtherData = 0 Then
...

感谢您的建议。

【问题讨论】:

为什么?除了将行减少几个字符并降低可读性(或至少是原始实现的“自我文档”)之外,还有什么好处? 看看here。它将准确显示它是如何完成的,但它也会向您显示 x64 上的相关错误 @sous2817 你可能是对的。我又想了想,我想要它主要是因为我的课程设计不佳。最初的原因是MyClass props 可以返回“修改”MyClass,或者修改oCollection 集合。很难(从道具名称)决定返回什么,所以我经常忘记添加.oCollection,它会抛出错误。但是我没有意识到问题是返回了错误的对象,并且倾向于在属性代码中搜索错误。 【参考方案1】:

您可以通过使用 Scripting.Dictionary 和 .items 或 .Keys 来避免 @CristianBuse 描述的错误。使用 for each 返回可以迭代的数组的方法。

在回答您的问题时,包装集合或脚本字典是一种很好的做法,因为它允许您对主机集合进行强类型化。您还可以使用包装代码为您的输入值添加验证或扩展主机集合的功能

下面的代码显示了脚本字典的包装、add 方法的验证以及简化向脚本字典添加数据的扩展。这些只是说明一点的例子

Option Explicit

Private Type State

    Host                As scripting.Dictionary
    
End Type

Private s               As State

Private Sub Class_Initialize()

    Set s.Host = New scripting.Dictionary
    
End Sub


Public Property Get Item(ByVal ipKey As Long) As String
    Item = s.Host.Item(ipKey)
End Property

Public Property Let Item(ByVal ipValue As String, ByVal ipKey As Long)
    s.Host.Item(ipKey) = ipValue
End Property


Public Sub Add(ByVal ipKey As Long, ByVal ipValue As String)

    If ipKey > 10 Then
    
        Err.Raise _
            5 + vbObjectError, _
            "Size Error", _
            "Object based on Class " & TypeName(Me) & " is limited to 0-9 members"
            
        End
        
    End If
    
    s.Host.Add ipKey, ipValue
    
End Sub

Public Sub AddByIndex(ByVal ipArray As Variant)

    Dim myArray As Variant
    
    If Not IsArray(ipArray) Then
    
        myArray = Array(ipArray)
        
    Else
    
        myArray = ipArray
        
    End If
    
    Dim myNextKey As Long
    myNextKey = s.Host.keys(s.Host.Count - 1)
    Do While s.Host.Exists(myNextKey)
    
        myNextKey = myNextKey + 1
        
    Loop
    
    
    Dim myItem As Variant
    For Each myItem In myArray
    
        s.Host.Add myNextKey, myItem
        myNextKey = myNextKey + 1
        
    Next
        
End Sub

Public Function Items() As Variant
    Items = s.Host.Items
End Function

所以你现在可以做

oclass.addbyindex Range("A1:A42").value

Dim myItem as Variant
For Each myItem in oClass.Items

【讨论】:

将数据包装到 Scripting.Dictionary 似乎是一种有用的技术,但它如何解决 Attribute [MethodName].VB_UserMemId = -4 错误?如果我理解正确,最好不要使用VB_UserMemId 属性并直接寻址集合oClass.oCollection 你还没看懂我的帖子。使用 scripting.dictionary 不会出现错误,因为在我提供的示例中,您使用 Scripting.Dictionary 的 .Items 方法返回包含项目数组(scripting.dictionary 中的值)和 for 循环的变体遍历提供的 items 数组。

以上是关于VBA:是不是可以创建一个行为类似于集合的类模块?的主要内容,如果未能解决你的问题,请参考以下文章

从类中加载配置,使其行为类似于属性

为 Excel VBA 创建常量库的理想方法是啥?

行为类似于 @Entity 和 @Embeddable 的类

iPhone - 行为类似于 UIViewController 的 UIView

vba字典删除重复

Ubuntu中的LibreOffice是不是有类似于Microsoft office(word,excel等)的vba宏的东西? [关闭]