Dans .NET, il existe deux catégories de types, les types de référence et les types de valeur .
Les structures sont des types de valeur et les classes sont des types de référence .
La différence générale est qu'un type de référence vit sur le tas et qu'un type de valeur vit en ligne, c'est-à-dire, où que ce soit votre variable ou champ est défini.
Une variable contenant un type de valeur contient la valeur entière du type de valeur. Pour une structure, cela signifie que la variable contient la structure entière, avec tous ses champs.
Une variable contenant un type de référence contient un pointeur ou une référence à un autre endroit de la mémoire où réside la valeur réelle.
Cela présente un avantage, pour commencer:
- les types de valeur contiennent toujours une valeur
- les types de référence peuvent contenir une référence nulle , ce qui signifie qu'ils ne font référence à rien du tout pour le moment
En interne, les types de référence sont implémentés en tant que pointeurs, et sachant que, et sachant comment fonctionne l'affectation des variables, il existe d'autres modèles de comportement:
- copier le contenu d'une variable de type valeur dans une autre variable, copie tout le contenu dans la nouvelle variable, ce qui rend les deux distinctes. En d'autres termes, après la copie, les modifications apportées à l'une n'affecteront pas l'autre
- copier le contenu d'une variable de type référence dans une autre variable, copie la référence, ce qui signifie que vous avez maintenant deux références vers le même stockage ailleurs des données réelles. En d'autres termes, après la copie, la modification des données dans une référence semblera également affecter l'autre, mais uniquement parce que vous regardez vraiment les mêmes données aux deux endroits
Lorsque vous déclarez des variables ou des champs, voici comment les deux types diffèrent:
- variable: le type de valeur se trouve sur la pile, le type de référence se trouve sur la pile en tant que pointeur vers quelque part dans la mémoire du tas où se trouve la mémoire réelle (bien que la série d'articles d'Eric Lipperts: la pile est un détail d'implémentation) ).
- class / struct-field: le type de valeur vit complètement à l'intérieur du type, le type de référence vit à l'intérieur du type en tant que pointeur vers quelque part dans la mémoire du tas où se trouve la mémoire réelle.
Lasse V. Karlsen
la source
Un bref résumé de chacun:
Cours uniquement:
Structures uniquement:
Classes et structures:
la source
c# struct memory overhead
et j'ai trouvé cette réponse de Hans Passant qui dit que non, ce n'est pas le cas non plus. Alors qu'est - ce que tu veux dire?class
sont de la mémoire gérée (gérée par le garbage collector), tandis que les instances destruct
ne le sont pas .Dans .NET, les déclarations de structure et de classe différencient les types de référence et les types de valeur.
Lorsque vous passez un type de référence, un seul est réellement stocké. Tout le code qui accède à l'instance accède au même.
Lorsque vous passez un type de valeur, chacun est une copie. Tout le code fonctionne sur sa propre copie.
Cela peut être montré avec un exemple:
Pour une classe, ce serait différent
Les classes ne peuvent être rien - la référence peut pointer vers une valeur nulle.
Les structures sont la valeur réelle - elles peuvent être vides mais jamais nulles. Pour cette raison, les structures ont toujours un constructeur par défaut sans paramètres - elles ont besoin d'une «valeur de départ».
la source
Différence entre Structs et Classes:
la source
Du choix de Microsoft entre la classe et la structure ...
la source
En plus de toutes les différences décrites dans les autres réponses:
Si vous recherchez une vidéo expliquant toutes les différences, vous pouvez consulter la Partie 29 - Tutoriel C # - Différence entre les classes et les structures en C # .
la source
Les instances de classes sont stockées sur le tas géré. Toutes les variables «contenant» une instance sont simplement une référence à l'instance sur le tas. Passer un objet à une méthode entraîne la transmission d'une copie de la référence, et non l'objet lui-même.
Les structures (techniquement, les types de valeur) sont stockées partout où elles sont utilisées, un peu comme un type primitif. Le contenu peut être copié par le runtime à tout moment et sans invoquer un constructeur de copie personnalisé. La transmission d'un type de valeur à une méthode implique la copie de la valeur entière, encore une fois sans invoquer de code personnalisable.
La distinction est améliorée par les noms C ++ / CLI: "ref class" est une classe telle que décrite en premier, "value class" est une classe telle que décrite en second. Les mots-clés "classe" et "struct" tels qu'utilisés par C # sont simplement quelque chose qui doit être appris.
la source
la source
Structure vs classe
Une structure est un type de valeur, elle est donc stockée sur la pile, mais une classe est un type de référence et est stockée sur le tas.
Une structure ne prend pas en charge l'héritage et le polymorphisme, mais une classe prend en charge les deux.
Par défaut, tous les membres de la structure sont publics, mais les membres de la classe sont par défaut de nature privée.
Comme une structure est un type de valeur, nous ne pouvons pas affecter null à un objet struct, mais ce n'est pas le cas pour une classe.
la source
Pour ajouter aux autres réponses, il y a une différence fondamentale qui mérite d'être notée, et c'est la façon dont les données sont stockées dans les tableaux car cela peut avoir un effet majeur sur les performances.
Donc, un tableau de structures ressemble à ceci en mémoire
[struct][struct][struct][struct][struct][struct][struct][struct]
Alors qu'un tableau de classes ressemble à ceci
[pointer][pointer][pointer][pointer][pointer][pointer][pointer][pointer]
Avec un tableau de classes, les valeurs qui vous intéressent ne sont pas stockées dans le tableau, mais ailleurs dans la mémoire.
Pour une grande majorité d'applications, cette différence n'a pas vraiment d'importance, cependant, dans le code haute performance, cela affectera la localisation des données dans la mémoire et aura un impact important sur les performances du cache CPU. Utiliser des classes quand vous auriez pu / auriez dû utiliser des structures augmentera massivement le nombre de cache manquant sur le CPU.
La chose la plus lente qu'un processeur moderne ne fait pas de croquer les nombres, c'est de récupérer des données de la mémoire, et un hit de cache L1 est beaucoup plus rapide que de lire des données de la RAM.
Voici du code que vous pouvez tester. Sur ma machine, l'itération à travers le tableau de classe prend environ 3 fois plus longtemps que le tableau struct.
la source
Juste pour le compléter, il y a une autre différence lors de l'utilisation du
Equals
méthode, qui est héritée par toutes les classes et structures.Disons que nous avons une classe et une structure:
et dans la méthode Main, nous avons 4 objets.
Alors:
Ainsi , les structures sont adaptées aux objets de type numérique, comme les points (enregistrer les coordonnées x et y). Et les cours conviennent aux autres. Même si 2 personnes ont le même nom, la même taille, le même poids ..., ce sont quand même 2 personnes.
la source
Eh bien, pour commencer, une structure est passée par valeur plutôt que par référence. Les structures sont bonnes pour les structures de données relativement simples, tandis que les classes ont beaucoup plus de flexibilité d'un point de vue architectural via le polymorphisme et l'héritage.
D'autres peuvent probablement vous donner plus de détails que moi, mais j'utilise des structures lorsque la structure que je recherche est simple.
la source
Outre la différence de base du spécificateur d'accès, et quelques-uns mentionnés ci-dessus, je voudrais ajouter quelques-unes des principales différences, y compris quelques-unes des mentionnées ci-dessus avec un exemple de code avec sortie, qui donnera une idée plus claire de la référence et de la valeur
Structures:
Classe:
Exemple de code
Production
La valeur initiale de Struct Object est: 10
Méthode de structure interne La valeur de méthode interne de l'objet Struct est: 20
Après la valeur d'appel de méthode de l'objet Struct est: 10
La valeur initiale de l'objet de classe est: 10
Méthode de classe interne La valeur de méthode interne de l'objet classe est: 20
Après que la valeur d'appel de méthode de l'objet de classe soit: 20
Ici, vous pouvez clairement voir la différence entre l'appel par valeur et l'appel par référence.
la source
Les événements déclarés dans une classe ont leur accès + = et - = automatiquement verrouillé via un verrou (this) pour les rendre sûrs pour les threads (les événements statiques sont verrouillés sur le type de la classe). Les événements déclarés dans une structure n'ont pas leur accès + = et - = automatiquement verrouillé. Un verrou (ceci) pour une structure ne fonctionnerait pas car vous ne pouvez verrouiller qu'une expression de type référence.
La création d'une instance de structure ne peut pas provoquer un garbage collection (sauf si le constructeur crée directement ou indirectement une instance de type référence) tandis que la création d'une instance de type reference peut provoquer un garbage collection.
Une structure a toujours un constructeur public par défaut intégré.
Cela signifie qu'une structure est toujours instanciable alors qu'une classe peut ne pas l'être car tous ses constructeurs peuvent être privés.
Une structure ne peut pas avoir de destructeur. Un destructeur est juste un remplacement d'objet.Finalize déguisé, et les structures, étant des types de valeur, ne sont pas soumises au garbage collection.
Une structure est implicitement scellée, une classe ne l'est pas.
Une structure ne peut pas être abstraite, une classe peut.
Une structure ne peut pas appeler: base () dans son constructeur alors qu'une classe sans classe de base explicite le peut.
Une structure ne peut pas étendre une autre classe, une classe peut.
Une structure ne peut pas déclarer des membres protégés (par exemple, des champs, des types imbriqués) qu'une classe peut.
Une structure ne peut pas déclarer les membres d'une fonction abstraite, une classe abstraite le peut.
Une structure ne peut pas déclarer les membres d'une fonction virtuelle, une classe le peut.
Une structure ne peut pas déclarer des membres de fonction scellés, une classe le peut.
Une structure ne peut pas déclarer les membres d'une fonction de substitution, une classe le peut.
La seule exception à cette règle est qu'une structure peut remplacer les méthodes virtuelles de System.Object, viz, Equals () et GetHashCode () et ToString ().
la source
Object
, qui contiendrait une référence à une copie encadrée de la structure.Comme mentionné précédemment: les classes sont de type référence tandis que les structures sont des types de valeur avec toutes les conséquences.
Comme un pouce de règle, Framework Design Guidelines recommande d'utiliser Structs au lieu de classes si:
la source
Il y a un cas intéressant de casse-tête "classe vs struct" - situation où vous devez renvoyer plusieurs résultats de la méthode: choisissez celui à utiliser. Si vous connaissez l'histoire ValueTuple - vous savez que ValueTuple (struct) a été ajouté car il devrait être plus efficace que Tuple (classe). Mais qu'est-ce que cela signifie en chiffres? Deux tests: l'un est struct / classe qui a 2 champs, l'autre avec struct / classe qui a 8 champs (avec dimension plus que 4 - la classe devrait devenir plus efficace que struct en termes de tics de processeur, mais bien sûr la charge GC devrait également être considérée ).
PS Une autre référence pour le cas spécifique «sturct ou classe avec collections» est là: https://stackoverflow.com/a/45276657/506147
Test de code:
la source
Cela est vrai, cependant, notez également que depuis .NET 2, les structures prennent en charge une version Nullable et C # fournit du sucre syntaxique pour le rendre plus facile à utiliser.
la source
(object)(default(int?)) == null
que vous ne pouvez pas faire avec un autre type de valeur, car il y a plus que du sucre ici. Le seul sucre estint?
pourNullable<int>
.Chaque variable ou champ d'un type de valeur primitif ou d'un type de structure contient une instance unique de ce type, y compris tous ses champs (publics et privés). En revanche, des variables ou des champs de types de référence peuvent être nuls ou faire référence à un objet, stocké ailleurs, sur lequel un certain nombre d'autres références peuvent également exister. Les champs d'une structure seront stockés au même endroit que la variable ou le champ de ce type de structure, qui peut être soit sur la pile, soit faire partie d' un autre objet tas.
La création d'une variable ou d'un champ d'un type de valeur primitif le créera avec une valeur par défaut; la création d'une variable ou d'un champ d'un type de structure créera une nouvelle instance, en créant tous les champs de la manière par défaut. La création d'une nouvelle instance d'un type de référence commence par la création par défaut de tous les champs, puis par l'exécution d'un code supplémentaire facultatif en fonction du type.
La copie d'une variable ou d'un champ d'un type primitif dans une autre copiera la valeur. La copie d'une variable ou d'un champ de type de structure vers une autre copiera tous les champs (publics et privés) de l'ancienne instance vers la dernière instance. La copie d'une variable ou d'un champ de type référence dans une autre fera que cette dernière se référera à la même instance que la première (le cas échéant).
Il est important de noter que dans certains langages comme C ++, le comportement sémantique d'un type est indépendant de la façon dont il est stocké, mais ce n'est pas le cas de .NET. Si un type implémente une sémantique de valeur mutable, la copie d'une variable de ce type dans une autre copie les propriétés de la première vers une autre instance, référencée par la seconde, et l'utilisation d'un membre de la seconde pour muter entraînera la modification de cette seconde instance. , mais pas le premier. Si un type implémente une sémantique de référence mutable, la copie d'une variable dans une autre et l'utilisation d'un membre de la seconde pour muter l'objet affecteront l'objet référencé par la première variable; les types avec une sémantique immuable ne permettent pas la mutation, donc peu importe sémantiquement si la copie crée une nouvelle instance ou crée une autre référence à la première.
Dans .NET, il est possible pour les types de valeur d'implémenter l'une des sémantiques ci-dessus, à condition que tous leurs champs puissent faire de même. Un type de référence, cependant, ne peut implémenter que la sémantique de référence mutable ou la sémantique immuable; les types de valeur avec des champs de types de référence mutables sont limités à l'implémentation d'une sémantique de référence mutable ou d'une sémantique hybride étrange.
la source