Создать зацикленный контейнерный класс в VBA - PullRequest
4 голосов
/ 28 марта 2019

Я пытался немного очистить свой код и сделать его более похожим на объектную модель Excel, и мне было интересно, возможно ли создать "Vableable" контейнерный класс в 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 ]

3 голосов
/ 28 марта 2019
Для выполнения итерации

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 + `) и вызовите Результаты проверки окно инструментов ( Ctrl + Shift + i ) - там должно быть число "Отсутствующий атрибут »Результаты в разделе« Rubberduck Oppor »«Настройки»:

inspection results

Нажмите «Исправить все вхождения в модуле» на нижней панели, чтобы синхронизировать скрытые атрибуты с комментариями аннотации.

Если у вас естьРезультаты «Отсутствует аннотация», Rubberduck определил, что модуль / элемент имеет значение не по умолчанию для данного атрибута, и может аналогичным образом добавить комментарий аннотации, который отображает / документирует его с комментарием.

Code Explorer ( Ctrl + R ), панель инструментов Rubberduck и собственный обозреватель объектов VBE ( F2 )) будет отображать содержимое атрибута VB_Description, поэтому аннотации @Description особенно полезны для любой открытой процедуры.

Обозреватель объектов:

Object Browser showing member description

Code Explorer:

Code Explorer showing member description

Панель инструментов Rubberduck:

RD toolbar showing member description

3 голосов
/ 28 марта 2019

Добавьте это к вашему классу

Public Function NewEnum() As IUnknown
Attribute NewEnum.VB_UserMemId = -4
    Set NewEnum = Items .[_NewEnum]
End Function
0 голосов
/ 29 марта 2019

Альтернативный подход к этой проблеме - не использование Collection, а Scripting.Dictionary.Одним из преимуществ словаря сценариев является то, что он может возвращать массивы ключей и элементов словаря.Перебор массива в VBA - тривиальное упражнение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...