Ограничить тип в коллекции внутри модуля класса - PullRequest
5 голосов
/ 17 апреля 2011

У меня есть коллекция внутри модуля класса.Я хотел бы ограничить тип объекта, который является «добавляемым» к этой коллекции, то есть коллекция должна принимать только объекты одного данного типа и ничего больше.

Есть ли способ принудительно установить тип объектов, добавляемых в коллекцию?

Из того, что я могу сказать, нет встроенного способа сделать это.Является ли решением сделать эту коллекцию закрытой и создать функции-оболочки для методов, обычно доступных для коллекций, то есть Add, Remove, Item и Count?

Я ненавижу иметьнаписать 3 функции-оболочки, которые не добавляют никакой функциональности, просто чтобы иметь возможность добавить принудительное приведение типов к методу Add.Но если это единственный путь, то это единственный путь.

Ответы [ 4 ]

5 голосов
/ 18 апреля 2011

Нет способа избежать функций-оболочек.Это просто присуще модели «специализация через сдерживание / делегирование», которую использует VBA.

Вы можете создать «пользовательский класс коллекции».Вы даже можете сделать его итеративным с помощью For...Each, но для этого требуется оставить VBA IDE и редактировать исходные файлы напрямую.

Сначала см. Раздел «Создание собственных классов коллекции» в старом Руководстве для программиста Visual Basic 6.0.:

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

Здесь также есть ответ на stackoverflow, который описывает то же самое:

vb6, эквивалентный списку

Тем не менее, они написаны для VB6, а не VBA.В VBA вы не можете выполнять часть «атрибутов процедуры» в IDE.Вы должны экспортировать модуль класса как текст и добавить его в текстовом редакторе.На сайте Дика Куслейки «Daily Dose of Excel» (как вы, наверное, знаете, Дик - постоянный участник стекового потока) есть сообщение от Роба ван Гелдера, показывающее, как это сделать:

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

В вашем случаеесли идти ко всем этим неприятностям - каждый класс «пользовательской коллекции» нуждается в собственном модуле - может быть, это того не стоит.(Если у вас есть только одно использование для этого, и он похоронен в другом классе, вы можете обнаружить, что не хотите раскрывать все функциональные возможности Collection в любом случае.)

3 голосов
/ 18 апреля 2011

Это то, что я сделал.Мне понравился пример Роба ван Гелдера, на который указывает @jtolle, но почему я должен довольствоваться созданием "пользовательского класса коллекции", который будет всегда принимать только один конкретный тип объекта (например, People), навсегда?Как отмечает @jtolle, это очень раздражает.

Вместо этого я обобщил идею и создал новый класс с именем 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

Затем метод 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

Все остальное примерно так же, как в примере (плюс некоторая обработка ошибок).Жаль, что RvG не прошел весь путь!Еще хуже, что Microsoft не включила подобные вещи в качестве встроенной функции ...

1 голос
/ 25 сентября 2015

Я сделал почти тот же код Жана-Франсуа Корбетта, но я адаптировался, потому что по какой-то причине не работал.

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

Затем, когда я хочу создать экземпляр из CCollection, я делаю каккод ниже:

    Set pFornecedores = New CCollection
    pFornecedores.Inicializar ("CEmpresa")

Где CEmpresa - тип класса из объекта, который я хочу

0 голосов
/ 18 апреля 2011

Да. Решение состоит в том, чтобы сделать вашу коллекцию частной, а затем сделать общедоступные функции-оболочки для добавления, удаления, получения, подсчета и т. Д.

Может показаться сложным написать дополнительный код, но это более надежное решение для инкапсуляции подобной коллекции.

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