Hola, encontramos la solución a tu interrogante, has scroll y la encontrarás más abajo.
Solución:
Deberías usar un Variant
en la primera función. Puede asignar un Object
a un Variant
, por ejemplo, esto no producirá un error:
Sub Test()
Dim var As Variant
Dim obj As Object
Set obj = Application
var = Application
Debug.Print var
End Sub
Pero esto le dará un Type Mismatch
error de compilación, es decir, tratando de asignar un Long
a una Object
:
Sub Test()
Dim obj As Object
Dim lng As Long
lng = 3
Set obj = lng
End Sub
Entonces, para una función genérica (a lo largo de las líneas de su código) para verificar si un Collection
key es válido, puede utilizar:
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
Código de prueba:
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
Hay un artículo útil sobre MSDN al respecto. El contexto es VB6 pero se relaciona con VBA.
Algunos errores tipográficos según los comentarios ya se han corregido durante la edición de su publicación. En respuesta a su pregunta, me gustaría cubrir aspectos relacionados.
Durante el uso keys en colecciones tiene principalmente tres ventajas
– Si el pedido cambia, su código seguirá accediendo al artículo correcto – Puede acceder directamente al artículo sin leer toda la colección
– Puede hacer que su código sea más legible.
* Pero al mismo tiempo hay principalmente tres problemas con el uso keys en colecciones
-
No puede comprobar si el key existe
-
No puedes cambiar el key
-
No puede recuperar el key
Según el artículo de Pearsons, las claves de una colección son de solo escritura; no hay forma de obtener una lista de las claves de una colección existentes. Continuando con el párrafo citado: –
Aquí, Coll es un objeto Collection en el que almacenaremos varios objetos CFile. La colección CollKeys se utiliza para almacenar keys de los objetos CFile almacenados en la Colección Coll. Necesitamos esta segunda colección porque las claves de una colección son de solo escritura; no hay forma de obtener una lista de las claves de una colección existentes. Una de las mejoras proporcionadas por CFiles es la capacidad de recuperar una lista de claves para la colección.
Clases de colección personalizadas
Una forma es iterar sobre los miembros de la colección y ver si hay una coincidencia con lo que está buscando y la otra forma es detectar la Item not in collection
error y luego establezca una bandera para decir que el elemento no existe. Las opiniones difieren sobre estos enfoques, mientras que algunas personas sienten que no es un buen método para detectar errores, mientras que otras secciones consideran que será significativamente más rápido que la iteración para cualquier colección de tamaño mediano a grande.
Entonces, si buscamos un método para detectar el error, el número de error que obtenemos depende exactamente de qué causó el error. Necesitamos una rutina de código para verificar el error. De la forma más sencilla podría ser.
'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
Las rutinas de detección de errores propuestas por varios profesionales difieren en el número de error que consideran importante e incluyen en su rutina. Varios números de error que ocurren comúnmente asociados con el objeto de recolección son:
Error 5
Argumento o llamada a procedimiento no válido. Este error también puede ocurrir si se intenta llamar a un procedimiento que no es válido en la plataforma actual. Por ejemplo, es posible que algunos procedimientos solo sean válidos para Microsoft Windows o para Macintosh, etc.error 438
“el objeto no admite esta propiedad o método Un objeto es una instancia de clase. Una instancia de clase admite algunas propiedades definidas en esa definición de tipo de clase y no admite esta.Error 457
Esta key ya está asociado con un elemento de esta colección. key para un miembro de la colección que ya identifica a otro miembro de la colección. Elija una diferente key
para este miembro.Error 91
Variable de objeto o variable de bloque With no establecida. Hay dos pasos para crear una variable de objeto. Primero debe declarar la variable de objeto. Luego debe asignar una referencia válida a la variable de objeto usando la instrucción Set. Intentó utilizar una variable de objeto que aún no hace referencia a un objeto válido.Error 450
Número incorrecto de argumentos o asignación de propiedad no válida. El número de argumentos en la llamada al procedimiento no era el mismo que el número de argumentos requeridos que esperaba el procedimiento. Si intentó asignar un valor a una propiedad de solo lectura,
Entre los errores anteriores, el error número 438 se ha considerado importante y el otro es 5. Estoy incorporando una rutina de función en mi programa de prueba de muestra que fue publicado por Mark Nold hace 7 años en 2008 vide SO pregunta Determinación de si un objeto es un miembro de una colección en VBA con el debido crédito a él.
Algunos errores, como el error 457, no se permitirán en el momento de la ejecución de la prueba del programa. Traté de poblar con duplicado keys datos, dio el error en el momento de la prueba del programa como se muestra en la instantánea.
Después de quitarlo, se muestra la salida correcta como se muestra en la instantánea.
Puede que no sea posible obtener la lista de keys de una colección con una colección vainilla sin almacenar el key valores en un independiente array. La alternativa más fácil para hacer esto es agregar una referencia a Microsoft Scripting Runtime y usar un diccionario más capaz en su lugar. He incluido este enfoque para obtener la lista de keys en mi programa.
Al poblar la Colección, se debe asegurar que el key es el segundo parámetro y debe ser único string.
El código completo de mi programa es.
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 salida final según el programa, como se muestra en la ventana Inmediato, se ha mostrado en la instantánea.
Quiero señalar que si desea que la función de PaulE sea un poco más flexible, puede cambiar el string parámetro a una variante, lo que significa que ahora también puede usarlo para verificar un elemento key o para un número de artículo, que es útil. Las variantes son un poco más lentas si va a verificar muchas colecciones, pero para la mayoría de los propósitos, las dos funciones actuarán de manera similar.
Function HasItem(col As Collection, ItemKeyOrNum As Variant) As Boolean
Dim v As Variant
On Error Resume Next
v = IsObject(col.Item(ItemKeyOrNum))
HasItem = Not IsEmpty(v)
End Function
La respuesta aceptada aquí es incorrecta (que es el caso de algunas otras preguntas que también he notado, así que tenga cuidado y lea todas las respuestas). Apostle y PaulE colaboraron allí para obtener la respuesta más correcta a la pregunta específica que se hizo. Intenté usar la respuesta aceptada, pero no funcionó.
La pregunta dice claramente: “¿Hay alguna manera de comprobar si un key está contenida en la Colección que funciona tanto para tipos como para objetos? “
La respuesta aceptada NO funciona para objetos. La respuesta de PaulE es la respuesta final y correcta. Solo estoy agregando un poco de matiz aquí para hacer que la función sea más única para todos.
Reseñas y valoraciones
Tienes la opción de patrocinar nuestro quehacer escribiendo un comentario y valorándolo te lo agradecemos.