J'ai différentes collections dans mon code. Certains contiennent des objets (de différents types), d'autres ont des types (comme Long).
Existe-t-il un moyen de vérifier si la collection contient une clé qui convient aux types et aux objets?
Jusqu'à présent, j'ai deux fonctions.
Première fonction:
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
Deuxième fonction:
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
La raison des deux fonctions est que ContainsObject ne semble pas fonctionner si je passe une collection qui a des paires longues (la fonction renvoie toujours False.)
P.S .: La première fonction est une copie de la troisième réponse de Tester ou vérifier si la feuille existe
Vous devriez utiliser une Variant
dans la première fonction. Vous pouvez affecter une Object
à une Variant
, par exemple. cela ne va pas erreur:
Sub Test()
Dim var As Variant
Dim obj As Object
Set obj = Application
var = Application
Debug.Print var
End Sub
Mais cela donnera une erreur de compilation Type Mismatch
, c’est-à-dire une tentative d’assigner une Long
à une Object
:
Sub Test()
Dim obj As Object
Dim lng As Long
lng = 3
Set obj = lng
End Sub
Ainsi, pour une fonction générique (le long des lignes de votre code) permettant de vérifier si une clé Collection
est valide, vous pouvez utiliser:
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
Code de test:
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
Il existe un article utile sur MSDN à ce sujet. Le contexte est VB6 mais concerne VBA.
Peu de fautes de frappe selon les commentaires ont déjà été corrigées lors de l'édition de votre message ..__ En réponse à votre question, j'aimerais aborder des aspects connexes.
Bien que l’utilisation de clés dans les collections présente principalement trois avantages
- Si la commande change, votre code aura toujours accès au bon article - Vous pouvez accéder directement à l'élément sans avoir à lire l'intégralité du collection
- Cela peut vous rendre le code plus lisible.
* Mais en même temps, il y a principalement trois problèmes d'utilisation de clés dans Collections
Vous ne pouvez pas vérifier si la clé existe
Vous ne pouvez pas changer la clé
Vous ne pouvez pas récupérer la clé
Selon l'article de Pearsons, les clés d'une collection sont en écriture seule - il n'y a aucun moyen d'obtenir une liste des clés existantes d'une collection. Passant plus loin au paragraphe cité: -
Ici, Coll est un objet Collection dans lequel nous allons stocker plusieurs Objets CFile. La collection CollKeys est utilisée pour stocker les clés de les objets CFile stockés dans la collection Coll. Nous avons besoin de cette seconde Collection parce que les clés d'une collection sont en écriture seule - il y a aucun moyen d'obtenir une liste des clés existantes d'une collection. Un de Les améliorations apportées par CFiles sont la possibilité de récupérer une liste de Touches pour la collection.
Classes de collection personnalisées
Une méthode consiste à parcourir les membres de la collection pour voir s'il existe une correspondance pour ce que vous recherchez et l'autre solution consiste à intercepter l'erreur Item not in collection
, puis à définir un indicateur indiquant que l'élément n'existe pas. Les opinions diffèrent sur ces approches alors que certaines personnes pensent que ce n'est pas une bonne méthode pour détecter les erreurs, tandis que d'autres sections pensent qu'elle sera beaucoup plus rapide que l'itération pour toute collection de moyenne à grande taille.
Donc, si nous choisissons une méthode pour intercepter l'erreur, le nombre d'erreur obtenu dépend exactement de la cause de l'erreur. Nous avons besoin d'une routine de code pour vérifier l'erreur. De la manière la plus simple possible.
'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
Les routines de saisie d'erreurs proposées par différents professionnels diffèrent par le numéro d'erreur qu'ils jugent important et les incluent dans leur routine. Divers numéros d'erreur courants associés à un objet de collecte sont les suivants: -
Error 5
Appel ou argument de procédure non valide. Cette erreur peut également se produire si vous tentez d'appeler une procédure non valide sur la plate-forme actuelle. Par exemple, certaines procédures peuvent n'être valables que pour Microsoft Windows, ou pour Macintosh, etc.error 438
"objet ne prend pas en charge cette propriété ou cette méthode. Un objet est une instance de classe. Une instance de classe prend en charge certaines propriétés définies dans cette définition de type de classe et ne les prend pas en charge.Error 457
Cette clé est déjà associée à un élément de thiscollection.Vous avez spécifié une clé pour un membre de la collection qui déjà identifie un autre membre de la collection. Choisissez une clé différente .__ pour ce membre.Error 91
Variable d'objet ou variable de bloc With non définie. Il existe deux étapes pour créer une variable d'objet. Tout d'abord, vous devez déclarer la variable d'objet Ensuite, vous devez affecter une référence valide à la variable object À l'aide de l'instruction Set. Vous avez tenté d'utiliser une variable d'objet .__ qui ne fait pas encore référence à un objet valide.Error 450
Nombre d'arguments incorrect ou propriété non valide assignation. Le nombre d'arguments dans l'appel de la procédure était différent du nombre d'arguments requis attendu par la procédure Si vous avez essayé d'assigner une valeur à une propriété en lecture seule,Parmi les erreurs ci-dessus, l'erreur numéro 438 a été jugée importante et l'autre est 5. J'intègre une routine de fonction dans mon programme de test d'échantillons qui a été posté par Mark Nold il y a 7 ans en 2008 vide SO question Déterminer si un objet est membre d'une collection dans VBA et lui est crédité.
Certaines erreurs telles que l'erreur 457 ne seront pas autorisées au moment de l'exécution du test du programme. J'ai essayé de remplir avec des données de clés en double, il a donné l'erreur au moment de tester le programme lui-même, comme indiqué dans l'instantané .
Après le retrait, le résultat est correct, comme indiqué dans le cliché instantané.
Il peut ne pas être possible d'obtenir la liste des clés d'une collection avec une collection Vanilla sans stocker les valeurs de clé dans un tableau indépendant. La solution la plus simple consiste à ajouter une référence à Microsoft Scripting Runtime et à utiliser un dictionnaire plus performant à la place de .. .. J'ai inclus cette approche pour obtenir la liste des clés dans mon programme.
Lors du remplissage de Collection, vous devez vous assurer que la clé est le deuxième paramètre et doit être une chaîne unique.
Le code complet de mon programme est.
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
La sortie finale selon le programme, comme indiqué dans la fenêtre Immédiat, a été affichée dans l’instantané.
La méthode de Robin échouera si la collection contient des objets plutôt que des types primitifs, car ils doivent être affectés à l'aide de Set et sinon générer une erreur entraînant le renvoi de la méthode par False. Voici un petit ajustement:
'Test if a key is available in a collection
Public Function HasKey(coll As Collection, strKey As String) As Boolean
On Error GoTo IsMissingError
Dim val As Variant
' val = coll(strKey)
HasKey = IsObject(coll(strKey))
HasKey = True
On Error GoTo 0
Exit Function
IsMissingError:
HasKey = False
On Error GoTo 0
End Function
Apôtre est presque correct avec leur réponse. La réponse de Robin ne fonctionnera pas avec des objets génériques, mais fonctionnera telle quelle, car l'objet Range d'Excel renverra la valeur de la cellule. J'adore l'utilisation d'IsObject par Apôtre (principalement parce que c'est ce que j'avais aussi compris). Le code est cependant un peu trop compliqué.
Si la clé existe dans la collection, IsObject définira la variante sur True ou False, sinon une erreur sera ignorée en laissant la variante vide.
Function HasKey(col As Collection, Key As String) As Boolean
Dim v As Variant
On Error Resume Next
v = IsObject(col.Item(Key))
HasKey = Not IsEmpty(v)
End Function