Background:
Ceci est une question de suivi sur cette question récente que j'ai posée sur la façon de renvoyer un tableau de propriétés du module Class directement à partir d'un élément Dictionary .
J'ai maintenant essayé ma façon de travailler avec Property Let et Property Get pour remplir un Private Array pour remplir le Dictionary avec. Cependant, en exécutant certains tests, j'ai rencontré une Erreur 438 .
Code: p>
Imaginez TstClass comme un module de classe avec le code suivant:
Sub Test()
Dim x As Long, arr As Variant, lst As Class1
Dim dict As Object: Set dict = CreateObject("Scripting.Dictionary")
For x = 1 To 3
Set lst = New Class1
lst.Add(0) = x
lst.Add(1) = x
lst.Add(2) = x
dict.Add x, lst
Next x
For x = 4 To 3 Step -1
If dict.Exists(x) = False Then
Set lst = New Class1
lst.Add(0) = x
lst.Add(1) = x
lst.Add(2) = x
dict.Add x, lst
Else
Set lst = dict(x)
lst.Add(1) = lst.Val(1) + 2
lst.Add(2) = lst.Val(2) + 2
dict(x) = lst '< Error 438 on this line
End If
Next x
For Each key In dict.keys
arr = dict(keys).GetArray
Next key
End Sub
Puis ce code à tester dans un module: p >
Private lst(0 To 2) As Variant
Public Property Let Add(ByVal i As Long, ByVal NewVal As Variant)
lst(i) = NewVal
End Property
Public Property Get Val(ByVal i As Long) As Variant
Val = lst(i)
End Property
Public Function GetArray() As Variant
GetArray = vals
End Function
Problème:
L'erreur 438 se produira sur dict (keyx) = lst et me dit que l'objet (un dictionnaire) ne prend pas en charge cette Propriété ou Méthode . Le problème me semble douteux car l'objet lst ne semble pas être un problème sur dict.Add x, lst . En fait, la méthode pour changer un Item via sa Key comme celle-ci semble être très pratique courante.
Question: p>
Alors que quelque chose comme Dict.Add x, "Hello" puis Dict (x) = "Hello World" semble fonctionner. Les erreurs de code lors de l'utilisation d'un objet Class dans la deuxième méthode. Quelqu'un sait-il pourquoi et si oui, comment résoudre ce problème?
Merci, JvdV
3 Réponses :
Set dict(keyx) = lst Since the variable lst refers to an object, Set is required here.
Il n'y a pas de variable déclarée comme «clé»
@Freeflow - Oui - cela aussi!
Le code OP a pas mal de fautes de frappe, de variables non déclarées et de propriété Let / Get utilisable mais pas «correcte». C'est ainsi que j'écrirais le code de l'op. Ayant maintenant été bien formé par les inspections de code du fantastique addin RubberDuck, je n'utilise plus les propriétés `` par défaut '' mais je m'assure d'utiliser le nom complet.
Code de classe
Sub Test()
Dim x As Long, arr As Variant, lst As Class1
Dim dict As Object: Set dict = CreateObject("Scripting.Dictionary")
For x = 1 To 3
Set lst = New Class1
lst.Item(0) = x
lst.Item(1) = x
lst.Item(2) = x
dict.Add x, lst
Next x
For x = 4 To 3 Step -1
If dict.Exists(x) = False Then
Set lst = New Class1
lst.Item(0) = x
lst.Item(1) = x
lst.Item(2) = x
dict.Add x, lst
Else
With dict.Item(x)
.Item(1) = lst.Item(1) + 2
.Item(2) = lst.Item(2) + 2
End With
End If
Next x
Dim myKey As Variant
For Each myKey In dict.Keys
arr = dict.Item(myKey).GetArray
Next Key
End Sub
'En général, VBA utilise le pluriel du' nom de l'élément 'lors du renvoi du tableau.
Public Function Items() As Variant
Items = p.List
End Function
Code du module
Option Explicit
Private Type Properties
List As Variant
End Type
Private p As Properties
Public Sub Class_Initialize()
ReDim p.List(2)
End Sub
Public Property Let Item(ByVal i As Long, ByVal NewVal As Variant)
p.List(i) = NewVal
End Property
Public Property Get Item(ByVal i As Long) As Variant
Item = p.List(i)
End Property
Merci pour vos commentaires, je l'examinerai quand je serai sur un PC demain plus. Acclamations! Btw, les fautes de frappe sont mon mauvais.
Comme Tim le souligne correctement , Set est requis ici, car lst est un objet.
Ce qui n'est pas clair, c'est pourquoi un mot-clé Set manquant entraînerait une erreur d'exécution 438, une erreur généralement rencontrée avec un code à liaison tardive bogué. La raison est, en un mot, let-coercion : en l'absence de mot-clé Set , une affectation est un Let (valeur) implicite affectation.
Si Class1 avait un membre par défaut , dict (keyx) = lst contraindrait le lst code > objet et stocker la valeur renvoyée par ce membre par défaut dans le dictionnaire.
Puisque Class1 n'a pas de membre par défaut (et que la référence n'est pas Nothing ), l'erreur 438 est générée (ce serait l'erreur 91 si lst était Rien ), car VBA cherche à appeler le membre avec un attribut VB_UserMemId = 0 , et ne peut pas le trouver.
L'erreur 438 se produira sur
dict (keyx) = lstet me dit que l'objet (unDictionary) ne prend pas en charge cette propriété ou méthode.
L'objet n'est pas le dictionnaire ici, mais votre instance de Class1 ; la "propriété ou méthode" manquante est le membre par défaut de cet objet, implicitement invoqué par let-coercion. Et comme l'appel du membre est implicite, il est facilement manqué, et le numéro / message d'erreur est facilement déroutant.
Rubberduck (projet de complément VBIDE gratuit et open source que je gère) déclenche un résultat d'inspection pour Valeur requise ici, qui explique exactement ce qui se passe:
Dans un contexte qui nécessite un type valeur, l'expression 'lst' de type d'objet 'VBAProject.Class1' est utilisée sans avoir de membre par défaut approprié.
Objet utilisé lorsqu'une valeur est requise
Le compilateur VBA ne génère pas d'erreur si un objet est utilisé à un endroit qui nécessite un type valeur et que le type déclaré de l'objet n'a pas de membre par défaut approprié. Dans presque toutes les circonstances, cela conduit à une erreur d'exécution 91 `` Objet ou avec variable de bloc non définie '' ou 438 `` L'objet ne prend pas en charge cette propriété ou cette méthode '' selon que l'objet a la valeur `` Rien '' ou non, ce qui est plus difficile à détecter et indique un bogue.
En d'autres termes, c'est l'un des nombreux endroits où le compilateur VBA reporte à l'exécution au lieu d'avertir de quelque chose de louche au moment de la compilation. L'analyse de code statique est donc le seul moyen de détecter de manière fiable de tels bogues avant qu'ils n'apparaissent au moment de l'exécution.
Merci pour l'explication approfondie Mathieu.
Set dict (keyx) = lstpuisquelstest un objetC'est simple ... merci @TimWilliams. Voulez-vous poster comme réponse pour fermer la question? J'ai passé littéralement des heures là-dessus: S
GetArray est incorrect. Vous renvoyez une variable «vals» qui n'est pas déclarée. Si votre intention est de renvoyer le tableau privé de la classe, votre code doit être getarray = lst. dict (keyx) devrait probablement être 'set dict.item (x)' (je préfère ne pas omettre la propriété par défaut). Et arr = dict (clés) .GetArray devrait probablement être arr = dict.item (clé) .GetArray.