Ich habe verschiedene Collections in meinem Code. Einige enthalten Objekte (verschiedener Art), andere haben Typen (wie Long).
Gibt es eine Möglichkeit, zu überprüfen, ob ein Schlüssel in der Collection enthalten ist, der für Typen sowie für Objekte geeignet ist?
Bisher habe ich zwei Funktionen.
Erste funktion:
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
Zweite Funktion:
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
Der Grund für die beiden Funktionen ist, dass ContainsObject nicht zu funktionieren scheint, wenn ich eine Collection mit Longs-Paaren übergeben (die Funktion gibt immer False zurück.)
P.S .: Die erste Funktion ist eine Kopie der dritten Antwort von Test oder Prüfung, ob ein Blatt vorhanden ist
Sie sollten eine Variant
in der ersten Funktion verwenden. Sie können eine Object
einer Variant
zuweisen, z. Das wird kein Fehler sein:
Sub Test()
Dim var As Variant
Dim obj As Object
Set obj = Application
var = Application
Debug.Print var
End Sub
Dies gibt jedoch einen Type Mismatch
-Kompilierungsfehler, d. H. Der Versuch, eine Long
einer Object
zuzuweisen:
Sub Test()
Dim obj As Object
Dim lng As Long
lng = 3
Set obj = lng
End Sub
Für eine generische Funktion (entlang der Zeilen Ihres Codes) zur Überprüfung, ob ein Collection
-Schlüssel gültig ist, können Sie Folgendes verwenden:
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
Testcode:
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
Zu MSDN gibt es einen nützlichen Artikel dazu. Der Kontext ist VB6, bezieht sich jedoch auf VBA.
Einige Tippfehler wie in den Kommentaren wurden bereits während der Bearbeitung Ihres Beitrags korrigiert .. __ Als Antwort auf Ihre Frage möchte ich verwandte Aspekte behandeln.
Das Verwenden von Schlüsseln in Sammlungen hat hauptsächlich drei Vorteile.
- Wenn sich die Bestellung ändert, greift Ihr Code immer noch auf den korrekten Artikel zu - Sie können direkt auf das Objekt zugreifen, ohne die gesamte .__ zu lesen. Sammlung
- Es kann den Code lesbarer machen.
* Aber gleichzeitig gibt es hauptsächlich drei Probleme bei der Verwendung von Schlüsseln in Sammlungen
Sie können nicht prüfen, ob der Schlüssel vorhanden ist
Sie können den Schlüssel nicht ändern
Sie können den Schlüssel nicht abrufen
Gemäß dem Pearsons-Artikel sind die Schlüssel einer Collection nur schreibgeschützt. Es gibt keine Möglichkeit, eine Liste der vorhandenen Keys einer Collection abzurufen. Weiter gehender zitierter Absatz: -
Hier ist Coll ein Collection-Objekt, in dem mehrere .__ gespeichert werden. CFile-Objekte. Die CollKeys-Sammlung wird zum Speichern der Schlüssel von .__ verwendet. die in der Coll Collection gespeicherten CFile-Objekte. Wir brauchen diese Sekunde Collection, da die Schlüssel einer Collection schreibgeschützt sind - Es gibt keine Möglichkeit, eine Liste der vorhandenen Schlüssel einer Sammlung abzurufen. Einer der Verbesserungen, die von CFiles bereitgestellt werden, sind die Möglichkeit, eine Liste von .__ abzurufen. Schlüssel für die Sammlung.
Benutzerdefinierte Sammelklassen
Eine Möglichkeit besteht darin, die Mitglieder der Auflistung zu durchlaufen und zu prüfen, ob Übereinstimmungen für das gefunden werden, wonach Sie suchen. Die andere Möglichkeit besteht darin, den Item not in collection
-Fehler abzufangen und dann ein Flag zu setzen, das besagt, dass das Element nicht vorhanden ist. Die Meinungen unterscheiden sich bei diesen Ansätzen, während einige Leute der Meinung sind, dass es keine gute Methode ist, um Fehler zu erkennen, während der andere Abschnitt der Ansicht ist, dass er für jede mittlere bis große Sammlung wesentlich schneller als die Iteration sein wird.
Wenn wir also eine Methode zum Abfangen von Fehlern suchen, dann hängt die Fehlernummer, die wir erhalten, davon ab, was genau den Fehler verursacht hat. Wir benötigen eine Code-Routine, um den Fehler zu überprüfen. Auf einfachste Weise könnte es sein.
'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
Die von verschiedenen Fachleuten vorgeschlagenen Routinen zum Erfassen von Fehlern unterscheiden sich in der Fehlernummer, die sie für wichtig halten und in ihre Routine aufnehmen. Verschiedene häufig auftretende Fehlernummern, die mit dem Auflistungsobjekt verknüpft sind, lauten:
Error 5
Ungültiger Prozeduraufruf oder -argument. Dieser Fehler kann auch auftreten , wenn versucht wird, eine Prozedur aufzurufen, die auf der aktuellen Plattform nicht gültig ist. Beispielsweise sind einige Verfahren möglicherweise nur fürMicrosoft Windows oder für den Macintosh usw. gültig.error 438
"object unterstützt diese Eigenschaft oder Methode nicht. Ein objectist eine Klasseninstanz. Eine Klasseninstanz unterstützt einige Eigenschaften , die in dieser Klassentypdefinition definiert sind, und unterstützt diese nicht.Error 457
Dieser Schlüssel ist bereits einem Element von this zugeordnetcollection. Sie haben einen Schlüssel für ein Sammlungsmitglied angegeben, das bereits ein anderes Mitglied der Sammlung identifiziert. Wählen Sie einen anderen Schlüssel Für dieses Mitglied.Error 91
Objektvariable oder With-Blockvariable nicht gesetzt. Zum Erstellen einer Objektvariablen gibt es zwei Schritte Zuerst müssen Sie die Objektvariable .__ deklarieren. Dann müssen Sie mit der Set-Anweisung einen gültigen Verweis auf die Variable des Objekts Zuweisen. Sie haben versucht, eine Objektvariable zu verwenden, die noch kein gültiges Objekt referenziert.Error 450
Falsche Anzahl von Argumenten oder ungültige Eigenschaft Zuordnung. Die Anzahl der Argumente im Aufruf der Prozedur stimmte nicht mit der Anzahl der erforderlichen Argumente überein, die von der -Prozedur erwartet wurden. Wenn Sie versucht haben, sie zuzuweisen einen Wert für eine schreibgeschützte Eigenschaft,Unter den obigen Fehlern wurde die Fehlernummer 438 als wichtig angesehen, und der andere ist 5. Ich füge eine Funktion-Routine in mein Beispieltestprogramm ein, die von Mark Nold vor 7 Jahren im Jahr 2008 veröffentlicht wurde. Vide SO question Determining ob ein Objekt Mitglied einer Sammlung in der VBA ist mit gebührender Anerkennung.
Einige Fehler wie der Fehler 457 sind zum Zeitpunkt des Programmtestlaufs nicht zulässig. Ich habe versucht, mit doppelten Schlüsseldaten aufzufüllen, es gab den Fehler zum Zeitpunkt des Programmtests, wie in der Momentaufnahme gezeigt
Nach dem Entfernen wird die korrekte Ausgabe angezeigt, wie im Schnappschuss gezeigt.
Es ist möglicherweise nicht möglich, die Liste der Schlüssel einer Sammlung mit einer Vanilla-Sammlung abzurufen, ohne die Schlüsselwerte in einem unabhängigen Array zu speichern. Die einfachste Alternative, dies zu tun, besteht darin, einen Verweis auf die Microsoft Scripting Runtime hinzuzufügen und stattdessen ein leistungsfähigeres Wörterbuch zu verwenden .. Diese Methode wurde hinzugefügt, um die Liste der Schlüssel in meinem Programm zu erhalten.
Beim Auffüllen von Collection muss sichergestellt werden, dass der Schlüssel der zweite Parameter ist und eine eindeutige Zeichenfolge sein muss.
Vollständiger Code meines Programms ist.
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
Die endgültige Ausgabe gemäß Programm, wie im Direktfenster gezeigt, wurde im Snapshot angezeigt.
Die Methode von Robin schlägt fehl, wenn die Collection Objekte statt primitiver Typen enthält, da diese mit Set zugewiesen werden müssen und ansonsten ein Fehler generiert wird, der dazu führt, dass die Methode False zurückgibt. Hier ist eine kleine Anpassung:
'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
Apostel ist mit ihrer Antwort fast richtig. Robins Antwort funktioniert nicht mit generischen Objekten, sondern funktioniert wie geschrieben, da das Range-Objekt von Excel den Wert der Zelle zurückgibt. Ich liebe die Verwendung von IsObject durch Apostel (vor allem, weil ich genau das herausgefunden hatte). Der Code ist jedoch etwas zu kompliziert.
Wenn der Schlüssel in der Auflistung vorhanden ist, setzt IsObject die Variante auf True oder False. Andernfalls wird ein Fehler ignoriert, wenn die Variante leer bleibt.
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