MGD Software
Messages postés193Date d'inscriptionvendredi 1 septembre 2006StatutMembreDernière intervention23 avril 2022
-
26 déc. 2017 à 17:19
MGD Software
Messages postés193Date d'inscriptionvendredi 1 septembre 2006StatutMembreDernière intervention23 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...
Whismeril
Messages postés18417Date d'inscriptionmardi 11 mars 2003StatutContributeurDernière intervention 5 juin 2023624 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
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 ?
Whismeril
Messages postés18417Date d'inscriptionmardi 11 mars 2003StatutContributeurDernière intervention 5 juin 2023624 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.
Vous n’avez pas trouvé la réponse que vous recherchez ?
MGD Software
Messages postés193Date d'inscriptionvendredi 1 septembre 2006StatutMembreDernière intervention23 avril 20222 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.