Общий способ проверить, находится ли ключ в коллекции в Excel VBA

у меня разные коллекции в моем коде. Некоторые из них содержат объекты (различных видов), другие имеют типы (например, длинные) внутри них.

есть ли способ проверить, содержится ли ключ в коллекции, которая работает как для типов, так и для объектов?

до сих пор у меня есть две функции.

функции:

Private Function ContainsObject(objCollection As Object, strName As String) As Boolean
    Dim o As Object
    On Error Resume Next
    Set o = objCollection(strName)
    ContainsObject = (Err.Number = 0)
    Err.Clear
End Function

вторая функция:

Private Function ContainsLong(AllItems As Collection, TheKey As String) As Boolean
    Dim TheValue As Long
    On Error Resume Next
    TheValue = AllItems.Item(TheKey)
    ContainsLong = (Err.Number = 0)
    Err.Clear
End Function

причина двух функций заключается в том, что ContainsObject, похоже, не работает, если я передаю Коллекция, имеющая пары Longs (функция всегда возвращает False.)

С. П.: первая функция является копией третьего ответа от проверить или проверить, существует ли лист

2 ответов


вы должны использовать Variant в первой функции. Вы можете назначить Object до Variant, например, это не ошибка:

Sub Test()
    Dim var As Variant
    Dim obj As Object
    Set obj = Application
    var = Application
    Debug.Print var
End Sub

но это даст Type Mismatch ошибка компиляции, т. е. пытается назначить Long до Object:

Sub Test()
    Dim obj As Object
    Dim lng As Long
    lng = 3
    Set obj = lng
End Sub

Итак, для общей функции (вдоль строк вашего кода), чтобы проверить, если Collection ключ действителен, вы можете использовать:

Function HasKey(coll As Collection, strKey As String) As Boolean
    Dim var As Variant
    On Error Resume Next
    var = coll(strKey)
    HasKey = (Err.Number = 0)
    Err.Clear
End Function

тестовый код:

Sub Test()
    Dim coll1 As New Collection
    coll1.Add Item:=Sheet1.Range("A1"), Key:="1"
    coll1.Add Item:=Sheet1.Range("A2"), Key:="2"
    Debug.Print HasKey(coll1, "1")

    Dim coll2 As New Collection
    coll2.Add Item:=1, Key:="1"
    coll2.Add Item:=2, Key:="2"
    Debug.Print HasKey(coll2, "1")
End Sub

есть полезная статья на MSDN относительно этого. Контекст-VB6, но относится к VBA.


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

*но в то же время есть are главным образом три проблемы с использованием ключей в сборники

  • вы не можете проверить, если ключ существует

  • вы не можете изменить ключ

  • вы не можете получить ключ

в соответствии со статьей Pearsons ключи коллекции доступны только для записи - нет способа получить список существующих ключей коллекции. Далее идет через quoted параграф: -

здесь Coll-это объект коллекции, в котором мы будем хранить несколько Объекты то cfile. Коллекция CollKeys используется для хранения ключей объекты CFile, хранящиеся в коллекции Coll. Нам нужна эта секунда. Коллекция, потому что ключи коллекции только для записи - есть невозможно получить список существующих ключей коллекции. Один из улучшения предоставляемых CFiles является возможность получения списка Ключи для Коллекция.

Пользовательские Классы Коллекций

один из способов-перебирать членов коллекции и посмотреть, есть ли совпадение для того, что вы ищете, а другой способ-поймать Item not in collection ошибка, а затем установите флаг, чтобы сказать, что элемент не существует. Мнения различаются по этим подходам, в то время как некоторые люди считают, что это не хороший метод, чтобы поймать ошибку, в то время как другой раздел чувствует, что это будет значительно быстрее, чем итерация для любое средство к большому собранию.
Поэтому, если мы идем на метод, чтобы поймать ошибку, то номер ошибки мы получаем зависит от того, что именно вызвало ошибку. Нам нужен код, чтобы проверить ошибку. В самом простом смысле.

'c1 is the collection
 For i = 1 To c1.Count
     Debug.Print Err.Number, Err.Description
     If Err.Number <> 0 Then Err.Clear
 Next i

процедуры обнаружения ошибок, предлагаемые различными специалистами, отличаются номером ошибки, который они считают важным и включают в свою рутину.Различные часто встречающиеся номера ошибок, связанные с объектом collection:-

  • Error 5 недопустимый вызов процедуры или аргумент.Эта ошибка также может произойти если предпринята попытка вызвать процедуру, которая недопустима на текущая платформа. Например, некоторые процедуры могут быть действительны только для В Microsoft Windows или для Macintosh, и так далее.
  • error 438 "объект не поддерживает это свойство или метод объект является экземпляром класса. Экземпляр класса поддерживает некоторые свойства определено в этом определении типа класса и не поддерживает вот этот.
  • Error 457 этот ключ уже связан с элементом этого коллекция.Вы указали ключ для члена коллекции, который уже идентифицирует другого члена коллекции. Выберите другой ключ для этого члена.
  • Error 91 объектная переменная или переменная блока With не задана.Есть два шаги по созданию переменной объекта. Сначала вы должны объявить объектная переменная. Затем необходимо назначить допустимую ссылку на объект переменная, использующая набор заявление. Вы пытались использовать объект переменной, которая еще не ссылается на допустимый объект.
  • Error 450 неверное число аргументов или недопустимое свойство назначение.Количество аргументов в вызове процедуры не совпадает количество обязательных аргументов процедура.Если вы попытались присвоить значение свойству только для чтения,

среди вышеуказанных ошибок номер ошибки 438 считается важным, а другой-5. Я включение рутины функции в мою программу тестирования образца, которая была опубликована Mark Nold 7 лет назад в 2008 году vide SO question определение того, является ли объект членом коллекции в VBA с должным уважением к нему.

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

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

no error

возможно, невозможно получить список ключей коллекции с коллекцией vanilla без сохранения значений ключей в независимом массиве. Самая простая альтернатива сделать это-добавить ссылку на Microsoft Scripting Runtime и вместо этого использовать более способный словарь. Я включил это подход, чтобы получить список ключей в моей программе.
При заполнении коллекции необходимо убедиться, что ключ является вторым параметром и должен быть уникальной строкой.

полный код моей программы.

Sub Generic_key_check()
    Dim arr As Variant
    Dim c1 As New Collection
    Dim dic As Object
    With Application
    .ScreenUpdating = False
    End With


    Set dic = CreateObject("Scripting.Dictionary")
    dic.CompareMode = vbTextCompare

    'Populate the collection
    c1.Add "sheet1", "sheet1"
    c1.Add "sheet2", "sheet2"
    c1.Add "sheet3", "sheet3"
    c1.Add "sheet4", "sheet4"
    c1.Add "sheet5", "sheet5"
    c1.Add 2014001, "Long1"
    c1.Add 2015001, "Long2"
    c1.Add 2016001, "Long3"
    c1.Add 2015002, "Long4"
    c1.Add 2016002, "Long5"

    'Populate the dictionary
    dic.Add "sheet1", "sheet1"
    dic.Add "sheet2", "sheet2"
    dic.Add "sheet3", "sheet3"
    dic.Add "sheet4", "sheet4"
    dic.Add "sheet5", "sheet5"
    dic.Add "Long1", 2014001
    dic.Add "Long2", 2015001
    dic.Add "Long3", 2016001
    dic.Add "Long4", 2015002
    dic.Add "Long5", 2016002
    ' Get a list of key items by Dictionary Method
    Dim N As Variant
    For Each N In dic.Keys
    Debug.Print "Key: " & N, "Value: " & dic.item(N)
    Next
    'Test for two types of data whether key exists or not.
    If InCollection(c1, "Long1") Then
    'If Exists("Long1", c1) Then
    Debug.Print "Good"

    Else
    ' If there is error then print out the error number and its description.
    Debug.Print Err.Number, Err.Description
    Debug.Print "Not Good"
    End If
    If InCollection(c1, "sheet2") Then
    Debug.Print "Good"

    Else
    Debug.Print Err.Number, Err.Description
    Debug.Print "Not Good"
    End If

    'Checking whether desired key has populated correctly
    Debug.Print c1("Sheet1")
    Debug.Print c1("Long3")



    'Listing out collection items to check theyexist in the collection.
    For i = 1 To c1.Count
    Debug.Print c1.item(i)
    Next i
    With Application
    .ScreenUpdating = True
    End With
    Set c1 = Nothing
End Sub
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

окончательный вывод в соответствии с программой, как показано в окне Immediate, был показан в моментальном снимке.
enter image description here