在VBA中创建一个可循环的容器类

时间:2019-03-28 16:15:00

标签: excel vba

我一直在尝试清理代码,使其与Excel对象模型更相似,我想知道是否有可能在VBA中创建“可循环”容器类,例如类似于您的操作方式:

Dim Sheet As Worksheet
For Each Sheet In ThisWorkbook.Worksheets
   ' ...
Next Sheet

我想要我自己的容器使用此功能。

假设我创建了自己的名为Container的类,其中包含某个类ItemType的项目(在该示例中,这可以是一个空类):

' Class Container
' The container contains items of a class I will call ItemType

Private Type MContainer
  Items As Collection ' Could also be implemented in terms of an array
End Type

Private This As MContainer

Public Property Get Item(ByVal Index As Long) As ItemType
Attribute Item.VB_UserMemId = 0 'Makes it so I can access elements like a Collection
  Set Item = This.Items(Index)
End Property

Public Function Add() As ItemType
  This.Items.Add
  Set Add = This.Items(This.Items.Count)
End Function

Private Sub Class_Initialize()
  Set This.Items = New Collection
End Sub

然后,我想使用For Each...遍历容器中的项目,但这不起作用。请参阅以下示例,了解我理想情况下的工作方式:

Public Sub MyMethod()

  Dim Stuff As New Container
  Stuff.Add

  Dim Element As ItemType
  For Each Element In Stuff ' <- This will not work
    ' Do something
  Next Element

End Sub

最后一个For循环是我要进行的工作。这可能吗?基本上,问题是我无法在我的For Each类上调用Container,类似于您使用类似的方法Excel.Sheets类。这可以在VBA中实现吗?

3 个答案:

答案 0 :(得分:3)

将此添加到您的班级

Public Function NewEnum() As IUnknown
Attribute NewEnum.VB_UserMemId = -4
    Set NewEnum = Items .[_NewEnum]
End Function

答案 1 :(得分:3)

For Each迭代需要一个特殊的成员属性值才能工作,并且需要一个NewEnum属性或函数才能返回IUnknown

每个可以通过For Each循环进行迭代的集合类都具有一个隐藏的[_NewEnum]成员(访问该隐藏成员需要方括号,因为下划线前缀对于VBA中的标识符是非法的

无法直接在VBE中进行模块和成员属性的调整,因此您需要删除/导出模块,然后在其中进行修改。 Notepad ++,保存更改,然后将其重新导入到您的项目中。

或者让Rubberduck(免责声明:我为这个开源项目做出了贡献)使用注释(又称“魔术评论”)为您完成此任务:

'@Enumerator
'@Description("Gets an enumerator that iterates through the internal object collection.")
Public Property Get NewEnum() As IUnknown
    Set NewEnum = this.Items.[_NewEnum]
End Function

'@DefaultMember
'@Description("Gets/sets the element at the specified index.")
Public Property Get Item(ByVal index As Long) As ItemType
    Set Item = this.Items(index)
End Property

然后解析项目( Ctrl + `)并打开 Inspection Results 工具窗口( Ctrl + Shift + i )-在“ Rubberduck机会”下应该有许多“缺少属性”结果:

inspection results

在底部窗格中单击“修复模块中的所有匹配项”,以将隐藏的属性与注释注释同步。

如果结果为“缺少注释”,Rubberduck已确定模块/成员具有给定属性的非默认值,并能够类似地添加注释注释,该注释注释/带有注释的表面/文档。 / p>

代码资源管理器 Ctrl + R ),Rubberduck工具栏和VBE自己的对象浏览器 F2 )将显示VB_Description属性的内容,因此@Description批注在任何公共过程中特别有用。

对象浏览器:

Object Browser showing member description

代码资源管理器:

Code Explorer showing member description

Rubberduck工具栏:

RD toolbar showing member description

答案 2 :(得分:0)

解决此问题的另一种方法是不使用Collection,而是使用Scripting.Dictionary。脚本字典的优点之一是它可以返回字典的键和项的数组。在VBA中遍历数组是一项微不足道的练习。