Choix entre classe et structure

Remarque

Ce contenu est réimprimé avec l’autorisation de Pearson Education, Inc. à partir des Instructions de conception d’une infrastructure : conventions, idiomes et modèles des bibliothèques réutilisables .NET, 2ème édition. Cette édition a été publiée en 2008, et le livre a été entièrement révisé dans la troisième édition. Certaines informations sur cette page peuvent être obsolètes.

L’une des décisions de conception de base prises par chaque concepteur d’infrastructure consiste à concevoir un type en tant que classe (type référence) ou en tant que struct (type valeur). Une bonne compréhension des différences dans le comportement des types référence et des types valeur est essentielle pour faire ce choix.

La première différence entre les types référence et les types valeur est que les types référence sont alloués sur le tas et récupérés par le récupérateur de mémoire, tandis que les types valeur sont alloués sur la pile ou inlined dans les types référencés et libérés lorsque la pile se déroule ou lorsque leur type conteneur est libéré. Par conséquent, les allocations et les désallocations de types valeur sont généralement moins coûteuses que les allocations et les désallocations des types référence.

Ensuite, les tableaux de types référence sont alloués hors ligne, ce qui signifie que les éléments de tableau sont simplement des références aux instances du type référence résidant sur le tas. Les tableaux de types valeur sont alloués inlined, ce qui signifie que les éléments de tableau sont les instances réelles du type valeur. Par conséquent, les allocations et les désallocations des tableaux de type valeur sont beaucoup moins coûteuses que les allocations et les désallocations des tableaux de type référence. En outre, dans une majorité de cas, les tableaux de types valeur présentent beaucoup mieux la localité de référence.

La différence suivante est liée à l’utilisation de la mémoire. Les types valeur sont boxed lorsqu’ils sont convertis en type référence ou en l’une des interfaces qu’ils implémentent. Ils sont unboxed lors de la conversion vers le type valeur. Étant donné que les zones sont des objets qui sont alloués sur le tas et récupérés par le récupérateur de mémoire, trop de boxing et d’unboxing peut avoir un impact négatif sur le tas, le récupérateur de mémoire et finalement les performances de l’application. En revanche, aucun boxing de ce genre ne se produit, car les types référence sont convertis. (Pour plus d’informations, consultez Conversion boxing et unboxing).

Ensuite, les affectations de type référence copient la référence, tandis que les affectations de type valeur copient la valeur entière. Par conséquent, les affectations de types référence volumineuses sont moins coûteuses que les affectations de types valeur volumineuses.

Enfin, les types référence sont passés par référence, tandis que les types valeur sont passés par valeur. Les modifications apportées à une instance d’un type référence affectent toutes les références pointant vers l’instance. Les instances de type valeur sont copiées lorsqu’elles sont passées par valeur. Lorsqu’une instance d’un type valeur est modifiée, elle n’affecte bien sûr aucune de ses copies. Étant donné que les copies ne sont pas créées explicitement par l’utilisateur, mais qu’elles sont implicitement créées lorsque les arguments sont passés ou les valeurs renvoyées, les types valeur qui peuvent être modifiés peuvent porter à confusion pour de nombreux utilisateurs. Par conséquent, les types valeur doivent être immuables.

En règle générale, la majorité des types d’une infrastructure doivent être des classes. Toutefois, il existe certaines situations dans lesquelles les caractéristiques d’un type valeur le rendent plus approprié pour utiliser des structs.

✔️ ENVISAGEZ de définir un struct au lieu d’une classe si les instances du type sont petites et généralement de courte durée ou sont généralement incorporées dans d’autres objets.

❌ ÉVITEZ de définir un struct, sauf si le type présente toutes les caractéristiques suivantes :

  • Il représente logiquement une valeur unique, similaire aux types primitifs (intdouble, etc.).

  • Il a une taille d’instance inférieure à 16 octets.

  • Il est immuable.

  • Il ne devra pas être fréquemment boxed.

Dans tous les autres cas, vous devez définir vos types en tant que classes.

Portions © 2005, 2009 Microsoft Corporation. Tous droits réservés.

Réimprimé avec l’autorisation de Pearson Education, Inc. et extrait de Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable .NET Libraries, 2nd Edition par Krzysztof Cwalina et Brad Abrams, publié le 22 octobre 2008 par Addison-Wesley Professional dans le cadre de la série sur le développement Microsoft Windows.

Voir aussi