Les structures
Introduction
Les structures (struct) existent depuis la première version du langage C# et la version 10 a apporté d'importantes modifications. Contrairement aux classes et aux records, les structures sont des types valeur. Elles sont particulièrement adaptées pour représenter des données simples, de petite taille et sans identité propre. Utilisées à bon escient, elles permettent de réduire les allocations mémoire et d'améliorer les performances de certaines applications.
Toutefois attention : une idée reçue consiste à penser qu'une structure est toujours allouée sur la pile (stack) et une classe sur le tas (heap). Ce n'est pas toujours vrai : l'emplacement mémoire dépend du contexte d'utilisation. Par exemple, une structure contenue dans une classe ou dans un tableau est elle aussi stockée dans le tas.
Quand utiliser une structure ?
Les structures sont particulièrement adaptées pour représenter des structures de données concernant des coordonnées (Point), une taille (Size), une couleur (Color), un montant (Money), une durée, une température, etc. D'une manière générale, l'utilisation d'une structure est adaptée dans les cas suivants :
-
Elle représente une valeur et non un objet métier
-
Elle est de "petite taille"
-
Elle est fréquemment créée
-
Elle n'a pas besoin d'être héritée
Aussi, le .NET Framework utilise très largement les structures, au travers des types suivants : DateTime, DateOnly, TimeOnly, Guid, TimeSpan, decimal, etc.
Présentation
Une structure se déclare à l'aide du mot-clé struct :
Elle peut être utilisée comme n'importe quel autre type :
Depuis la version 10 du langage C#, les structures peuvent également utiliser des constructeurs explicites :
public struct Point
{
public int X { get; set; }
public int Y { get; set; }
public Point(int x, int y)
{
X = x;
Y = y;
}
}
Ainsi on peut écrire :
Comportement d'une structure lors de l'affectation
La principale différence avec une classe est qu'une structure est un type valeur. Lorsque nous affectons une structure à une autre variable :
Les valeurs contenues dans point1 sont copiées dans point2. Si nous modifions ensuite point2 :
Alors :
Les deux propriétés sont totalement indépendantes.
À l'inverse, avec une classe, les deux variables point1 et point2 auraient référencé le même objet, ainsi la modification d'une propriété d'une variable aurait affecté l'autre (car il s'agit du même objet).
Comparaison entre deux structures
Les structures ne possèdent pas de notion d'identité. Lorsque nous écrivons :
La variable result vaut true, car la méthode Equals() compare les valeurs contenues dans la structure.
Les limites des structures
Les structures possèdent également quelques limitations. Contrairement aux classes :
-
Elles ne peuvent pas hériter d'une autre structure ou d'une classe
-
Elles ne peuvent pas servir de type de base pour une autre structure
-
Elles sont copiées à chaque affectation ou passage de paramètres (sauf si utilisation de
ref,in,out)
Pour cette raison, nous devons si possible ne pas créer des structures volumineuses, car leur copie peut devenir coûteuse.
Les structures immuables
Comme pour les records, il est souvent recommandé de rendre les structures immuables. Pour cela, le langage C# propose les mots-clés readonly struct :
public readonly struct Point
{
public int X { get; }
public int Y { get; }
public Point(int x, int y)
{
X = x;
Y = y;
}
}
Une fois créée, une telle structure ne peut plus être modifiée.