Quelques raccourcis :
C# trace une distinction entre les struct, qu'il nomme aussi « types valeurs », et les class. Bien que le support offert aux class dans ce langage soit supérieur à celui offert aux struct, les deux familles de types ont leur rôle à jouer.
Cet article survole quelques caractéristiques clés des struct en C#.
C# supporte deux grandes familles de types : les types « valeurs » et les types « références ». Techniquement, un type valeur est un struct, et un type référence est un class.
La relation entre ces deux types est très différente de celle qu’on rencontre en C++, où struct et class sont presque interchangeables. En , par exemple, int est un alias pour System.Int32, qui est un struct.
Notez que plusieurs diront que « les instances de types références sont allouées sur le tas » et que « les instances de types valeurs sont allouées sur la pile ». En pratique, ceci tend à s’avérer, mais nous ne pouvons compter là-dessus de manière portable (ce n’est pas documenté ainsi).
Puisque les struct sont souvent placés sur la pile ou insérés à même la définition d’une classe, la recommandation officielle à leur égard est de restreindre les struct aux types qui sont à la fois :
Les struct, contrairement aux class, sont manipulés directement. Cela peut jouer un rôle dans un schème de saine gestion de la mémoire.
Par exemple, dans l'exemple à droite, où le type Point est un class, le tableau pts est fait de références contiguës en mémoire, mais les référés de ces références sont épars. Ceci impacte à la fois l'espace occupé par le tableau et la vitesse d'accès aux éléments (car les accès indirects aux objets sont moins Cache-Friendly que les accès directs) |
|
Il serait tentant de simplement remplacer class par struct et d'espérer pour le mieux, mais cela ne fonctionnera pas car les règles (pour des raisons parfois obscures) pour l'initialisation d'un struct sont différentes de celles qui prévalent pour l'initialisation d'un class. Par exemple, initialiser une propriété à la déclaration n'est pas possible pour un struct. On peut spéculer que l'idée est qu'instancier un struct par défaut réalise un memset() sur l'espace mémoire de cet objet, pour des raisons d'efficacité, mais c'est de la spéculation |
|
L'écriture correcte est celle proposée à droite :
|
|
La principale caractéristique des struct est que les objets de cette famille de types sont manipulés directement, alors que les objets dont les types sont de la famille des class sont manipulés indirectement. Ceci a pour conséquence que copier un struct copie bel et bien le struct, alors que copier une référence sur un class crée un alias, une situation où deux références partagent un même référé.
À titre d'exemple, si nous supposons un Point représenté sous forme d'un class, alors dans le programme principal visible à droite, l'expression suivante :
... fait pointer pt1 au même endroit que pt0. Aucun Point n'est copié, malgré les apparences; nous faisons ainsi une copie de référence, pas une copie de référé. Conséquemment, l'expression suivante :
... modifie le référé de pt1, qui est aussi le référé de pt0. Ainsi, pt0.X et pt1.X sont une seule et même entité, et les deux affichages montrent 1 à l'écran. |
|
Maintenant, si nous supposons un Point représenté sous forme d'un struct, alors dans le programme principal visible à droite, l'expression suivante :
... fait de pt1 une copie de pt0. Il y a alors bel et bien copie d'un Point, par copie d'une référence sur un Point. Conséquemment, l'expression suivante :
... modifie pt1, qui est un objet distinct de pt0. Ainsi, les deux affichages montrent respectivement 0 et 1 à l'écran. |
|
Quelques liens pour enrichir le propos.