Var2 = Var1; Var2.prop = x; Résultat : Var1.prop != x.

MGD Software Messages postés 186 Date d'inscription vendredi 1 septembre 2006 Statut Membre Dernière intervention 23 avril 2022 - 26 déc. 2017 à 17:19
MGD Software Messages postés 186 Date d'inscription vendredi 1 septembre 2006 Statut Membre Dernière intervention 23 avril 2022 - 26 déc. 2017 à 19:32
Bonjour,
J'ai un petit souci avec les variables objet
Jusqu'à présent, je pensait que quand on faisait Var2 = Var1, les deux variables pointaient sur le même objet.
Toute modification dans l'une se retrouvait dans l'autre.
Or à l'expérience, je me suis rendu compte que ce n'est pas vrai, en tout cas lorsqu'on fait un cast.

Voici mon problème un peu plus détaillé.
Dans un ListView, je mets dans la propriété Tag des ListViewItems une structure ListEntry comportant (entre autres) un membre "action". Ce membre fait partie d'un enum Action qui énumère (!) les différents types d'actions à effectuer quand on clique sur l'item.
Et voici ce qui m'arrive :
ListEntry LE = (ListEntry)Item.Tag;
Console.WriteLine(LE.action);			// Renvoie "create"
LE.action = Action.delete;
Console.WriteLine(((ListEntry)(Item.Tag)).action);	// Renvoie toujours "create"


A priori, le Tag de l'item n'est pas mis à jour.
J'utilise la variable LE pour simplifier le code, qui est beaucoup complexe que ci-dessus. Et je ne suis pas sûr qu'en faisant :
((ListEntry)Item.Tag).action = Action.delete
le tag soit bien mis à jour. D'ailleurs quand j'essaie, j'obtiens : "error CS0445: Impossible de modifier le résultat d'une conversion unboxing"
Par contre, si j'écris
Item.Tag = LE
, ça fonctionne. En fait, j'ai carrément remplacé tout l'objet Tag, au lieu de le modifier. Ce n'est pas vraiment pratique, et dans d'autres cas ça peut ne pas être possible.

Y a-t-il une fonction particulière pour que deux variables pointent vers le même objet, même à travers un cast?
En C et C++, j'utilisais un pointeur. Mais je n'ai pas trouvé l'équivalent en C#.

PS : j'ai été voir ce qu'était le Boxing sur la MSDN, et je n'ai rien compris...

5 réponses

Whismeril Messages postés 19023 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 18 avril 2024 656
Modifié le 26 déc. 2017 à 18:44
Bonsoir,
en C#, les types de bases (sauf string), les enums et les structures sont des types « valeur », c’est à dire qu’ils stockent la valeur de la constantes.
Tous les autres sont des types références (un peu comme les pointeurs).
Tag est un object et object est un type de base.
Une petite verif vite fait sur un site de coding en ligne


Cependant, (et la je ne peux pas vérifier avec le site de coding en ligne) si on place un type reference dans le Tag, je pense que ça devrait marcher.
Dans ton texte tu as dit que ListEntry est une structure, et la struture est un type valeur.

Quand j'étais petit, la mer Morte n'était que malade.
George Burns
0
Whismeril Messages postés 19023 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 18 avril 2024 656
26 déc. 2017 à 18:46
Maitnenant, la bonne question à se poser est : y a t’il besoin du cast?

Si je comprends, l’item en question est du type ListEntry, et tu l’as mis aussi dans le Tag?
0
MGD Software Messages postés 186 Date d'inscription vendredi 1 septembre 2006 Statut Membre Dernière intervention 23 avril 2022 2
26 déc. 2017 à 19:02
En effet. C'est quand même pas simple.

J'ai eu le même problème en voulant modifier le membre action dans une List<T>, mais cette fois à la compilation et non à l'exécution :

List<ListEntry> mCompList = new List<ListEntry>();
...
mCompList[i].action = Action.none;      // Erreur CS1612

En allant lire la doc sur l'erreur CS1612, j'ai appliqué la méthode indiquée dans la doc, et ça marche :

ListEntry LE = mCompList[i];
LE.action = Action.none;
mComplist[i] = LE;

CQFD.

Je me demande s'il n'aurait pas été plus simple de créer un classe n'ayant que des membres {get;set;} au lieu d'une structure. Je pense que je n'aurais pas eu ce problème. Mais est-ce plus efficace en terme de vitesse et d’occupation mémoire ? Quelle différence au niveau du code ?
0
Whismeril Messages postés 19023 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 18 avril 2024 656
26 déc. 2017 à 19:15
En terme, d’occupation de mémoire, une classe est un type référence, donc chaque fois qu’elle est « transmise », c’est juste une référence, un pointeur, donc peu de mémoire.
Pour un type valeur, tout ce qu’il contient est copié, donc forcément avec une structure avec plein de champs, chaque copie va prendre beaucoup de place.
En terme de vitesse, je ne sais pas.
Et au niveau du code, ben y a juste {get; set;} en plus.
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
MGD Software Messages postés 186 Date d'inscription vendredi 1 septembre 2006 Statut Membre Dernière intervention 23 avril 2022 2
26 déc. 2017 à 19:32
Merci.
Je pense que désormais, j'utiliserai des classes.

J'ai relu l'article de la MSDN sur le boxing, et il en ressort qu'en terme de performance c'est pas le top: le framework n'arrête pas de copier les types valeur dans des objets. Il y a même la démonstration que la modif qu'une variable valeur, passée dans un objet, modifiée dans cet objet et récupérée en valeur n'est en fait pas modifiée. C'est exactement ce qui m'arrive.
https://docs.microsoft.com/fr-fr/dotnet/csharp/programming-guide/types/boxing-and-unboxing

Et pour répondre à la question précédente, le cast est forcément nécessaire pour récupérer la structure :
ListEntry => Tag (boxing) : pas de problème puisque Tag est un objet
Tag => ListEntry (unboxing) : cast obligatoire car l'objet est générique et ne connait pas les membres de la structure.

Bon, j'aurai encore appris quelque chose...

Mais j'apprécie beaucoup en C# la faculté la propriété Tag des contrôles qui en possèdent, qui peut être n'importe quoi, alors qu'en VB6 ce ne pouvait être qu'une chaine, ce qui obligeait à faire des constructions compliquées pour stocker plusieurs valeurs.
0
Rejoignez-nous