Определение того, является ли объект членом коллекции в VBA
Как определить, является ли объект членом коллекции в VBA?
в частности, мне нужно выяснить, является ли определение таблицы членом TableDefs
коллекция.
14 ответов:
лучше всего перебирать элементы коллекции и посмотреть, соответствуют ли они тому, что вы ищете. Поверьте мне, мне приходилось делать это много раз.
второе решение (что намного хуже) состоит в том, чтобы поймать ошибку "Item not in collection", а затем установить флаг, чтобы сказать, что элемент не существует.
разве это не достаточно хорошо?
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
не совсем элегантно, но лучшее (и самое быстрое) решение, которое я мог найти, было использование 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
Это старый вопрос. Я внимательно просмотрел все ответы и комментарии, проверенные решения для исполнения.
Я придумал самый быстрый вариант для моей среды, которая не терпит неудачу, когда коллекция имеет объекты, а также примитивы.
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
.
Я создал это решение из приведенных выше предложений, смешанных с решением 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
вы можете сократить предлагаемый код для этого, а также обобщить для непредвиденных ошибок. Здесь вы идете:
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
в вашем конкретном случае (TableDefs) итерация по коллекции и проверка имени-хороший подход. Это нормально, потому что ключ для коллекции (имя) является свойством класса в коллекции.
но в общем случае коллекций VBA ключ не обязательно будет частью объекта в коллекции (например, вы можете использовать коллекцию в качестве словаря с ключом, который не имеет ничего общего с объектом в коллекции). В этом случае, у вас нет выбор, но попытаться получить доступ к элементу и поймать ошибку.
У меня есть некоторые редактирования, лучше всего работает для коллекций:
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
эта версия работает для примитивных типов и классов (включая короткий тестовый метод)
' 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
это требует некоторых дополнительных настроек в случае, если элементы в коллекции не являются объектами, а массивы. Кроме того, он отлично работал для меня.
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
для случая, когда ключ не используется для сбора:
Public Function Contains(col As Collection, thisItem As Variant) As Boolean Dim item As Variant Contains = False For Each item In col If item = thisItem Then Contains = True Exit Function End If Next End Function
Не мой код, но я думаю, что это довольно красиво написано. Он позволяет проверять по ключу, а также по самому объектному элементу и обрабатывает как метод on Error, так и итерацию по всем элементам коллекции.
https://danwagner.co/how-to-check-if-a-collection-contains-an-object/
Я не буду копировать полное объяснение, так как они доступны по ссылке. Само решение копируется в случае, если страница в конечном итоге становится недоступной в будущее.
сомнение, которое у меня есть в коде, - это чрезмерное использование GoTo в первом блоке If, но это легко исправить для всех, поэтому я оставляю исходный код как есть.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' 'INPUT : Kollection, the collection we would like to examine ' : (Optional) Key, the Key we want to find in the collection ' : (Optional) Item, the Item we want to find in the collection 'OUTPUT : True if Key or Item is found, False if not 'SPECIAL CASE: If both Key and Item are missing, return False Option Explicit Public Function CollectionContains(Kollection As Collection, Optional Key As Variant, Optional Item As Variant) As Boolean Dim strKey As String Dim var As Variant 'First, investigate assuming a Key was provided If Not IsMissing(Key) Then strKey = CStr(Key) 'Handling errors is the strategy here On Error Resume Next CollectionContains = True var = Kollection(strKey) '<~ this is where our (potential) error will occur If Err.Number = 91 Then GoTo CheckForObject If Err.Number = 5 Then GoTo NotFound On Error GoTo 0 Exit Function CheckForObject: If IsObject(Kollection(strKey)) Then CollectionContains = True On Error GoTo 0 Exit Function End If NotFound: CollectionContains = False On Error GoTo 0 Exit Function 'If the Item was provided but the Key was not, then... ElseIf Not IsMissing(Item) Then CollectionContains = False '<~ assume that we will not find the item 'We have to loop through the collection and check each item against the passed-in Item For Each var In Kollection If var = Item Then CollectionContains = True Exit Function End If Next var 'Otherwise, no Key OR Item was provided, so we default to False Else CollectionContains = False End If End Function
Я сделал это так, вариация на Vadims код, но для меня немного более читаемым:
' Returns TRUE if item is already contained in collection, otherwise FALSE Public Function Contains(col As Collection, item As String) As Boolean Dim i As Integer For i = 1 To col.Count If col.item(i) = item Then Contains = True Exit Function End If Next i Contains = False End Function
Я написал этот код. Я думаю, это может помочь кому-то...
Public Function VerifyCollection() For i = 1 To 10 Step 1 MyKey = "A" On Error GoTo KillError: Dispersao.Add 1, MyKey GoTo KeepInForLoop KillError: 'If My collection already has the key A Then... count = Dispersao(MyKey) Dispersao.Remove (MyKey) Dispersao.Add count + 1, MyKey 'Increase the amount in relationship with my Key count = Dispersao(MyKey) 'count = new amount On Error GoTo -1 KeepInForLoop: Next End Function