par , 25/10/2021 à 21h32 (1313 Affichages)
Copier une variable object en VBA revient à créer un clone de cet objet, mais encore faut-il qu'il le permette
Salut
- Pierre, j'ai passé un objet ByVal à une procédure, mais quand je modifie la variable copiée, l'original est aussi modifié... Au secours!!
- Toi, tu as essayé de copier un objet...
- Ben oui, Y a rien dans le VBA pour copier un objet, faut bien se débrouiller, mais là, on dirait que mon code se fout du byVal
- Et tu sais pourquoi?
- ...
- Parce qu'effectivement, le VBA se fout de ByVal lorsque tu l'utilises pour un objet. Autrement dit, ByRef ou ByVal, c'est kif pour un objet
- Ok. Et comment je fais pour copier l'objet, moi?
Deux variables, un même objet
imaginons une classe perso très simple, oTest:
1 2 3
| Option Explicit
Public Color As String |
Examinons l'exécution du code suivant:
Que va-t-il se passer après l'exécution de la ligne en jaune? Quelle sera la couleur myObject? "Bleu" ou "Rouge"? La réponse est "Rouge"!
Explications
Lorsque l'on affecte une variable objet à une variable, on ne crée pas de copie, mais bien un "pointeur" vers le même objet, c'est-à-dire le même emplacement mémoire.
Copie via une fonction avec argument ByVal
Dans l'intro, mon pote me disait avoir essayé un ByVal pour passer une "copie" de l'objet. En effet, passage d'argument à une fonction est ByRef par défaut, ce qui signifie que l'on passe la variable à la fonction. Si l'on passe l'argument par ByVal, on passe en fait une copie. Si vous examinez le code ci-dessous, vous voyez que a a été modifié, mais pas b, passée en ByVal.
Ce fonctionnement n'est cependant valide que pour des variables primaires. Pour les objets, le passage d'arguments est toujours ByRef, même si vous le spécifiez ByVal.
Conclusion provisoire
VBA n'expose pas d'outil pour copier un objet. si l'on veut copier un objet, il faudra écrire une procédure qui s'en chargera.
Clonage procédural
On comprendra ici que j'ai volontairement simplifié l'objet. Un objet informatique contiendra souvent plusieurs propriétés qu'il faudra copier. J'ai à peine complexifié la classe pour attribuer un nom à l'objet qui sera "en lecture seule", afin de modéliser les cas qui pourront se présenter à vous. Voici le code adapté de notre classe oTest
1 2 3 4 5 6 7 8 9 10 11 12 13
| Option Explicit
Public Color As String
Private mName As String
Sub Init(Name As String)
mName = Name
End Sub
Property Get Name() As String
Name = mName
End Property |
Voici l'exécution d'une procédure de copie de l'objet
On constate donc ici qu'il y a bien eu copie, la ligne Set Copy = New oTest ayant créé un objet vide qui a été valorisé. MyObject est resté bleu alors myObject2 est devenu rouge.
Copie "orientée objet"
Tant qu'à créer une classe perso, autant y intégrer la procédure de copie, qui est souvent nommée Clone. Elle procédera de la même façon que la procédure vue plus haut
Dans la mesure ou Name ne peut être adapté que via Init, on pourrait imaginer que le clone recoive un nouveau nom
1 2 3 4 5 6 7
| Property Get Clone(Optional Name As String) As oTest
Set Clone = New oTest
With Clone
.Init IIf(Name = "", mName, Name)
.Color = Color
End With
End Property |
Conclusions
Comme on le voit, la copie d'un objet doit être pensée et sera normalement prévue au sein de l'objet pour respecter l'orientation objet d'une part, et rendre le module de classe autonome par rapport à une procédure de copie externe.
Bon travail avec vos classes perso