Определение того, является ли объект членом коллекции в VBA - PullRequest
58 голосов
/ 26 сентября 2008

Как определить, является ли объект членом коллекции в VBA?

В частности, мне нужно выяснить, является ли определение таблицы членом коллекции TableDefs.

Ответы [ 14 ]

69 голосов
/ 14 июня 2009

Разве это не достаточно хорошо?

Public Function Contains(col As Collection, key As Variant) As Boolean
Dim obj As Variant
On Error GoTo err
    Contains = True
    obj = col(key)
    Exit Function
err:

    Contains = False
End Function
39 голосов
/ 20 октября 2008

Не совсем элегантно, но лучшее (и самое быстрое) решение, которое я смог найти, - это использование OnError. Это будет значительно быстрее, чем итерация для любой средней и большой коллекции.

Public Function InCollection(col As Collection, key As String) As Boolean
  Dim var As Variant
  Dim errNumber As Long

  InCollection = False
  Set var = Nothing

  Err.Clear
  On Error Resume Next
    var = col.Item(key)
    errNumber = CLng(Err.Number)
  On Error GoTo 0

  '5 is not in, 0 and 438 represent incollection
  If errNumber = 5 Then ' it is 5 if not in collection
    InCollection = False
  Else
    InCollection = True
  End If

End Function
21 голосов
/ 26 сентября 2008

Лучше всего перебрать членов коллекции и посмотреть, соответствует ли то, что вы ищете. Поверь мне, мне приходилось делать это много раз.

Второе решение (что намного хуже) состоит в том, чтобы отловить ошибку «Предмет не в коллекции», а затем установить флаг, чтобы сказать, что предмет не существует.

9 голосов
/ 22 января 2018

Это старый вопрос. Я внимательно изучил все ответы и комментарии, проверил решения на производительность.

Я предложил самый быстрый вариант для моей среды, который не выходит из строя, когда в коллекции есть объекты и примитивы.

Public Function ExistsInCollection(col As Collection, key As Variant) As Boolean
    On Error GoTo err
    ExistsInCollection = True
    IsObject(col.item(key))
    Exit Function
err:
    ExistsInCollection = False
End Function

Кроме того, это решение не зависит от жестко закодированных значений ошибок. Таким образом, параметр col As Collection может быть заменен некоторой другой переменной типа коллекции, и функция все еще должна работать. Например, в моем текущем проекте он будет иметь вид col As ListColumns.

3 голосов
/ 04 июня 2014

Вы можете сократить предложенный код для этого, а также обобщить для непредвиденных ошибок. Вот, пожалуйста:

Public Function InCollection(col As Collection, key As String) As Boolean

  On Error GoTo incol
  col.Item key

incol:
  InCollection = (Err.Number = 0)

End Function
3 голосов
/ 23 ноября 2012

Я создал это решение из вышеупомянутых предложений, смешанных с решением microsofts для итерации по коллекции.

Public Function InCollection(col As Collection, Optional vItem, Optional vKey) As Boolean
On Error Resume Next

Dim vColItem As Variant

InCollection = False

If Not IsMissing(vKey) Then
    col.item vKey

    '5 if not in collection, it is 91 if no collection exists
    If Err.Number <> 5 And Err.Number <> 91 Then
        InCollection = True
    End If
ElseIf Not IsMissing(vItem) Then
    For Each vColItem In col
        If vColItem = vItem Then
            InCollection = True
            GoTo Exit_Proc
        End If
    Next vColItem
End If

Exit_Proc:
Exit Function
Err_Handle:
Resume Exit_Proc
End Function
2 голосов
/ 03 января 2015

У меня есть некоторые изменения, лучше всего работает для коллекций:

Public Function Contains(col As collection, key As Variant) As Boolean
    Dim obj As Object
    On Error GoTo err
    Contains = True
    Set obj = col.Item(key)
    Exit Function
    
err:
    Contains = False
End Function
2 голосов
/ 26 сентября 2008

В вашем конкретном случае (TableDefs) итерация коллекции и проверка Имени - это хороший подход. Это нормально, потому что ключ для коллекции (Name) является свойством класса в коллекции.

Но в общем случае коллекций VBA ключ не обязательно будет частью объекта в коллекции (например, вы можете использовать коллекцию в качестве словаря с ключом, который не имеет ничего общего с объектом в коллекция). В этом случае у вас нет выбора, кроме как попытаться получить доступ к элементу и поймать ошибку.

1 голос
/ 06 февраля 2014

эта версия работает для примитивных типов и для классов (включая короткий метод тестирования)

' TODO: change this to the name of your module
Private Const sMODULE As String = "MVbaUtils"

Public Function ExistsInCollection(oCollection As Collection, sKey As String) As Boolean
    Const scSOURCE As String = "ExistsInCollection"

    Dim lErrNumber As Long
    Dim sErrDescription As String

    lErrNumber = 0
    sErrDescription = "unknown error occurred"
    Err.Clear
    On Error Resume Next
        ' note: just access the item - no need to assign it to a dummy value
        ' and this would not be so easy, because we would need different
        ' code depending on the type of object
        ' e.g.
        '   Dim vItem as Variant
        '   If VarType(oCollection.Item(sKey)) = vbObject Then
        '       Set vItem = oCollection.Item(sKey)
        '   Else
        '       vItem = oCollection.Item(sKey)
        '   End If
        oCollection.Item sKey
        lErrNumber = CLng(Err.Number)
        sErrDescription = Err.Description
    On Error GoTo 0

    If lErrNumber = 5 Then ' 5 = not in collection
        ExistsInCollection = False
    ElseIf (lErrNumber = 0) Then
        ExistsInCollection = True
    Else
        ' Re-raise error
        Err.Raise lErrNumber, mscMODULE & ":" & scSOURCE, sErrDescription
    End If
End Function

Private Sub Test_ExistsInCollection()
    Dim asTest As New Collection

    Debug.Assert Not ExistsInCollection(asTest, "")
    Debug.Assert Not ExistsInCollection(asTest, "xx")

    asTest.Add "item1", "key1"
    asTest.Add "item2", "key2"
    asTest.Add New Collection, "key3"
    asTest.Add Nothing, "key4"
    Debug.Assert ExistsInCollection(asTest, "key1")
    Debug.Assert ExistsInCollection(asTest, "key2")
    Debug.Assert ExistsInCollection(asTest, "key3")
    Debug.Assert ExistsInCollection(asTest, "key4")
    Debug.Assert Not ExistsInCollection(asTest, "abcx")

    Debug.Print "ExistsInCollection is okay"
End Sub
1 голос
/ 29 февраля 2012

Требуются некоторые дополнительные корректировки в случае, если элементы в коллекции не объекты, а массивы. Кроме этого он работал нормально для меня.

Public Function CheckExists(vntIndexKey As Variant) As Boolean
    On Error Resume Next
    Dim cObj As Object

    ' just get the object
    Set cObj = mCol(vntIndexKey)

    ' here's the key! Trap the Error Code
    ' when the error code is 5 then the Object is Not Exists
    CheckExists = (Err <> 5)

    ' just to clear the error
    If Err <> 0 Then Call Err.Clear
    Set cObj = Nothing
End Function

Источник: http://coderstalk.blogspot.com/2007/09/visual-basic-programming-how-to-check.html

...