Quelle est la différence entre un type de référence et un type de valeur en c#?
un type m'a posé cette question il y a quelques mois et je n'ai pas pu l'expliquer en détail. Quelle est la différence entre un type de référence et un type de valeur en C#?
je sais que les types de valeur sont int
, bool
, float
, etc et les types de référence sont delegate
, interface
, etc. Ou est-ce mal?
pouvez-vous me l'expliquer de façon professionnelle?
14 réponses
vos exemples sont un peu étranges parce que tandis que int
, bool
et float
sont des types spécifiques, les interfaces et les délégués sont types de type - tout comme struct
et enum
sont des types de valeur.
j'ai écrit an explication des types de référence et des types de valeur dans cet article . Je serais heureux de développer sur les morceaux que vous trouvez confus.
la version" TL;DR " est de penser à ce qu'est la valeur d'une variable/expression d'un type particulier. Pour un type de valeur, la valeur est l'information elle-même. Pour un type de référence, la valeur est une référence qui peut être nul ou peut-être un moyen d'accéder à un objet contenant les informations.
Par exemple, pensez à une variable comme un morceau de papier. Il pourrait avoir la valeur "5" ou "false" écrit dessus, mais il ne pourrait pas avoir ma maison... il aurait à avez instructions à ma maison. Ces directions sont l'équivalent d'une référence. En particulier, deux personnes pourraient avoir différents morceaux de papier contenant les mêmes directions à ma maison - et si une personne a suivi ces directions et peint ma maison rouge, alors la deuxième personne verrait que le changement aussi. S'ils avaient tous les deux photos de ma maison sur le papier, alors une personne colorant leur papier ne changerait pas l'autre personne de papier.
Type de valeur:
contient une certaine valeur pas des adresses mémoire
exemple:
Struct
stockage:
TL;DR : la valeur d'une variable est stockée partout où elle est décélérée. Les variables locales vivent sur la pile par exemple, mais lorsqu'elles sont déclarées dans une classe comme membre, elles vivent sur le tas étroitement couplé avec la classe elle est déclarée.
plus : ainsi les types de valeurs sont stockés où qu'ils soient déclarés.
Par exemple: une valeur int
's à l'intérieur d'une fonction en tant que variable locale serait stockée sur la pile, tandis qu'une valeur int
' s déclarée en tant que membre dans une classe serait stockée sur le tas avec la classe dans laquelle elle est déclarée. Un type de valeur sur une classe a un lifetype c'est exactement le même que la classe elle est déclarée, nécessitant presque pas de travail pour le éboueur. C'est plus compliqué Cependant, je me réfère au Livre de @JonSkeet " C# in Depth "ou à son article" Memory in .NET " pour une explication plus concise.
avantages:
un type de valeur n'a pas besoin de collecte supplémentaire des ordures. Il collecte les ordures avec l'endroit où il vit. Les variables locales dans les méthodes se nettoyer sur la méthode de congé.
Inconvénients:
-
quand un grand ensemble de valeurs est passé à une méthode la variable de réception copie effectivement de sorte qu'il y a deux valeurs redondantes dans la mémoire.
-
car les cours ne sont pas compris.il perd tous les avantages oop
Type de référence:
contient une mémoire l'adresse d'une valeur non valeur
exemple:
Classe
stockage:
stocké sur tas
avantages:
-
lorsque vous passez une variable de référence à une méthode et qu'elle change effectivement la valeur originale alors que dans les types de valeur une copie de la donnée la variable est prise et sa valeur est changée.
-
lorsque la taille de la variable est plus grande le type de référence est bon
-
comme les classes viennent comme des variables de type de référence, ils donnent la réutilisabilité, bénéficiant ainsi de la programmation orientée objet
Inconvénients:
plus de référencement de travail lors de l'attribution et déréférence lors de la lecture de la valeur.surcharge supplémentaire pour le collecteur d'ordures
j'ai trouvé plus facile de comprendre la différence des deux si vous savez comment l'ordinateur allouer des étoffes en mémoire et savoir ce qu'est un pointeur.
La référenceest généralement associée à un pointeur. Ce qui signifie que l'adresse mémoire où votre variable réside est en fait la tenue une autre adresse mémoire de l'objet réel dans un emplacement de mémoire différent.
l'exemple que je m'apprête à donner est grossièrement terminé simplifié, afin de prendre cela avec un grain de sel.
Imaginez la mémoire de l'ordinateur est un tas de boîtes postales dans une rangée (de départ w/ Boîte POSTALE 0001 à une Boîte POSTALE n) qui peut contenir quelque chose à l'intérieur. Si PO boxes ne le fait pas pour vous, essayez un hashtable ou un dictionnaire ou un tableau ou quelque chose de similaire.
Ainsi, quand vous faites quelque chose comme:
var a = "Bonjour";
l'ordinateur fera ce qui suit:
- attribuent la mémoire (disons à partir de l'emplacement de la mémoire 1000 pour 5 octets) et mettent H (à 1000), e (à 1001), l (à 1002), l (à 1003) et o (à 1004).
- attribuer quelque part dans la mémoire (disons à l'emplacement 0500) et assigné comme la variable A.
Donc c'est un peu comme un alias (0500 est une). - assignez la valeur à cet emplacement de mémoire (0500) à 1000 (qui est l'endroit où la chaîne Hello commence en mémoire). Ainsi la variable a contient une référence à l'emplacement réel de la mémoire de départ de la chaîne" Hello". Le type de valeur
retiendra la chose réelle dans son emplacement de mémoire.
Ainsi, quand vous faites quelque chose comme:
var a = 1;
l'ordinateur fera ce qui suit:
- attribuer un emplacement mémoire dire à 0500 et l'attribuer à la variable a (le même alias chose)
- y ajoute la valeur 1 (à l'emplacement mémoire 0500).
Notez que nous n'allouons pas de mémoire supplémentaire pour conserver la valeur réelle (1). Ainsi, a détient en fait la "valeur réelle et c'est pourquoi on l'appelle type de valeur.
ceci provient d'un de mes billets d'un autre forum, il y a environ deux ans. Alors que la langue est vb.net (par opposition à C#), les concepts de Type de valeur et de type de référence sont uniformes dans l'ensemble de .net, et les exemples sont toujours valables.
il est également important de se rappeler que dans .net, tous les types dérivent techniquement de l'objet de type de base. Les types de valeurs sont conçus pour se comporter comme tels, mais en fin de compte ils héritent également de la fonctionnalité de l'objet de type de base.
A. Les types de valeurs sont juste cela - ils représentent une zone distincte dans la mémoire où une valeur discrète est stockée. Les types de valeurs sont de taille mémoire fixe et sont stockés dans la pile, qui est une collection d'adresses de taille fixe.
quand vous faites une déclaration comme celle-ci:
Dim A as Integer
DIm B as Integer
A = 3
B = A
vous avez fait ce qui suit:
- a créé 2 espaces en mémoire suffisants pour contenir des valeurs entières de 32 bits.
- a placé une valeur de 3 dans l'allocation mémoire attribuée à un
- a placé une valeur de 3 dans la mémoire assignée à B en lui assignant la même valeur que celle retenue en A.
La Valeur de chaque variable existe discrètement dans chaque emplacement de mémoire.
B. Les types de référence peuvent être de différentes tailles. Par conséquent, ils ne peuvent pas être stockés dans la "pile" (rappelez - vous, la pile est une collection de les allocations de mémoire de taille fixe?). Ils sont stockés dans le "Tas Managé". Les pointeurs (ou "références") de chaque élément sur le tas managé sont maintenus dans la pile (Comme une Adresse). Votre code utilise ces pointeurs dans la pile pour accéder aux objets stockés dans le tas géré. Ainsi, lorsque votre code utilise une variable de référence, il utilise en fait un pointeur (ou "adresse" vers un emplacement de mémoire dans le tas géré).
dites que vous avez créé une classe nommée clesperson, avec une corde Propriétaire.Nom
Dans ce cas, lorsque vous faites une déclaration telle que:
Dim p1 As clsPerson
p1 = New clsPerson
p1.Name = "Jim Morrison"
Dim p2 As Person
p2 = p1
dans le cas ci-dessus, le p1.Name Property retournera "Jim Morrison", comme vous vous y attendiez. La p2.La propriété Name retournera aussi "Jim Morrison", comme vous vous y attendiez. Je crois que p1 et p2 représentent des adresses distinctes sur la pile. Cependant, maintenant que vous avez attribué à p2 la valeur de p1, p1 et p2 pointent vers le même endroit sur la tas managé.
considérez maintenant cette situation:
Dim p1 As clsPerson
Dim p2 As clsPerson
p1 = New clsPerson
p1.Name = "Jim Morrison"
p2 = p1
p2.Name = "Janis Joplin"
dans cette situation, vous avez créé une nouvelle instance de la classe personne sur le tas géré avec un pointeur p1 sur la pile qui renvoie à l'objet, et assigné à la propriété Nom de L'instance objet une valeur de" Jim Morrison " à nouveau. Ensuite, vous avez créé un autre pointeur p2 dans la pile, et l'avez pointé à la même adresse sur le tas géré que celle référencée par p1 (quand vous avez fait la cession p2 = p1).
voici le twist. Lorsque vous attribuez la propriété Name de p2 à la valeur "Janis Joplin" , vous changez la propriété Name de l'objet référencé par p1 et p2, de sorte que, si vous exécutez le code suivant:
MsgBox(P1.Name)
'Will return "Janis Joplin"
MsgBox(p2.Name)
'will ALSO return "Janis Joplin"Because both variables (Pointers on the Stack) reference the SAME OBJECT in memory (an Address on the Managed Heap).
ça avait du sens?
dernier. Si vous faites cela:
DIm p1 As New clsPerson
Dim p2 As New clsPerson
p1.Name = "Jim Morrison"
p2.Name = "Janis Joplin"
vous avez maintenant deux objets de personne distincts. Cependant, à la minute où vous le faites encore une fois:
p2 = p1
vous avez maintenant pointé les deux vers"Jim Morrison". (Je ne sais pas exactement ce qui est arrivé à l'objet sur le tas référencé par p2 . . . Je PENSE qu'il est aujourd'hui hors de portée. C'est l'un de ces domaines où hopefullly quelqu'un peut me droite . . .). - EDIT: je crois que c'est pour cela que vous définiriez p2 = Nothing ou p2 = New clesperson avant de faire la nouvelle affectation.
encore une fois, si vous faites maintenant ceci:
p2.Name = "Jimi Hendrix"
MsgBox(p1.Name)
MsgBox(p2.Name)
les deux boîtes msg vont maintenant retourner "Jimi Hendrix "
cela peut être assez confus pour un peu, et je dirai une dernière fois, je peux avoir certains des détails erronés.
bonne chance, et j'espère que d'autres qui savent mieux que moi viendront pour aider à clarifier certains de cela . . .
type de données de valeur et type de données de référence
1) valeur (contenir les données directement ) mais référence (se réfère aux données)
2) dans valeur (chaque variable a sa propre copie)
mais
dans référence (plus que variable peut se référer à certains les objets)
3) dans valeur (la variable de fonctionnement ne peut avoir d'effet sur une autre variable ) mais dans de référence (variable peut affecter d'autres )
4) les types de valeurs sont (int, bool, float) mais type de référence sont (tableau , les objets de la classe , string )
" les Variables qui sont basées sur les types de valeurs contiennent directement des valeurs. Attribuer une variable de type de valeur à une autre copie la valeur contenue. Cela diffère de l'assignation des variables de type de référence, qui copie une référence à l'objet mais pas à l'objet lui-même."de la bibliothèque de Microsoft.
, Vous pouvez trouver une réponse plus complète ici et ici .
parfois les explications ne seront pas utiles surtout pour les débutants. Vous pouvez imaginer le type de valeur comme fichier de données et le type de référence comme raccourci vers un fichier.
donc si vous copiez une variable de référence vous copiez seulement le lien/pointeur vers une donnée réelle quelque part dans la mémoire. Si vous copiez un type de valeur, vous clonez vraiment les données dans la mémoire.
c'est probablement faux de manière ésotérique, mais, pour faire simple:
types de Valeur sont des valeurs qui sont passées normalement "par valeur (copie). Les types de référence sont passés "par référence" (donnant ainsi un pointeur à la valeur originale). Il n'y a aucune garantie par la norme ECMA.net quant à l'endroit où ces "choses" sont sauvegardées. Vous pouvez construire une implémentation de .NET qui est stackless, ou une implémentation qui est heapless (la seconde serait très complexe, mais vous pourrait, en utilisant des fibres et de nombreuses piles)
les Structures sont de type valeur (int, bool... sont des structures, ou du moins sont simulés comme...), les classes sont des types de référence.
Les types de valeursdescendent du système.ValueType. Le type de référence descend du système.Objet.
maintenant.. En fin de compte, vous avez Type de valeur, "objets référencés" et des références (en C++, ils seraient appelés pointeurs vers des objets. Dans .NET ils sont opaques. Nous ne savons pas ce qu'ils sont. De notre point de vue, ce sont des "poignées" vers l'objet). Ces derniers sont similaires aux types de valeurs (ils sont passés par copie). Ainsi un objet est composé par l'objet (un type de référence) et zéro ou plus de références à celui-ci (qui sont similaires aux types de valeur). Lorsqu'il n'y a aucune référence, le GC la recueillera probablement.
en général( dans l'implémentation "par défaut" de .NET), le type de valeur peut aller sur la pile (si ce sont des champs locaux) ou sur le tas (si ce sont des champs d'une classe, si ce sont des variables dans une fonction itératrice, si ce sont des variables référencées par une fermeture, si elles sont variables dans une fonction asynchrone (en utilisant le nouveau CTP asynchrone)...). La valeur référencée ne peut aller qu'au tas. Les références utilisent les mêmes règles que les types de valeurs.
dans les cas de type de valeur qui vont sur le tas parce qu'ils sont dans une fonction iterator, une fonction async, ou sont référencés par une fermeture, si vous regardez le fichier compilé, vous verrez que le compilateur a créé une classe pour mettre ces variables, et la classe est construite lorsque vous appelez la fonction.
maintenant, je ne sais pas écrire des choses longues, et j'ai de meilleures choses à faire dans ma vie. Si vous voulez une version "précise" "académique" "correcte", lisez ceci:
http://blogs.msdn.com/b/ericlippert/archive/2010/09/30/the-truth-about-value-types.aspx
c'est 15 minutes que je cherche! C'est mieux que les versions msdn, parce que c'est un article condensé "prêt à l'emploi".
la façon la plus simple de penser aux types de référence est de les considérer comme étant des" object-IDs"; les seules choses qu'on peut faire avec un object ID sont créer un, copier un, demander ou manipuler le type d'un, ou comparer deux pour l'égalité. Une tentative de faire autre chose avec un objet-ID sera considérée comme un raccourci pour faire l'action indiquée avec l'objet visé par cette id.
supposons que j'ai deux variables X et Y du type de voiture--un type de référence. Y arrive de tenir "object ID #19531". Si je dis "X=Y", cela fera que X tiendra"object ID #19531". Notez que ni X ni Y ne détient une voiture. La voiture, aussi appelée "object ID # 19531", est entreposée ailleurs. Quand J'ai copié Y dans X, je n'ai fait que copier le numéro D'identification. Supposons que je dise X. Couleur=Couleurs.Bleu. Une telle déclaration sera considérée comme une instruction pour aller trouver "object ID#19531" et le peindre en bleu. Notez que même si X et Y font maintenant référence à une voiture bleue plutôt qu'à une voiture jaune, la déclaration n'affecte pas réellement X ou Y, parce que les deux font toujours référence à "object ID # 19531", qui est toujours la même voiture comme il a toujours été.
les types de variables et la valeur de référence sont faciles à appliquer et bien appliqués au modèle de domaine, facilitent le processus de développement.
pour supprimer tout mythe autour de la quantité de" type de valeur", je commenterai sur la façon dont cela est traité sur la plate-forme. NET, spécifiquement en C # (CSharp) quand on appelle APIS et envoyer des paramètres par valeur, par référence, dans nos méthodes et fonctions et comment faire le traitement correct des passages de ces valeurs.
lire cet article valeur du type Variable et référence dans C #
Suppose v
est une expression/variable de type valeur, et r
est une expression / variable de type référence
x = v
update(v) //x will not change value. x stores the old value of v
x = r
update(r) //x now refers to the updated r. x only stored a link to r,
//and r can change but the link to it doesn't .
ainsi, une variable de type valeur stocke la valeur réelle (5, ou"h"). Un varaible de type de référence ne stocke qu'un lien vers une boîte métaphorique où la valeur est.
types de valeur sont passés par leur valeur et les types référence, de par leur référence (adresse mémoire).
cela signifie que les changements apportés aux paramètres de type de valeur (les paramètres formels) à l'intérieur d'une méthode appelée ne refléteront pas les valeurs à partir desquelles la méthode a été appelée (les paramètres réels).
mais les modifications apportées aux paramètres de référence à l'intérieur d'une méthode appelée se refléteront dans les modifications apportées aux variables déclarées dans l'appel méthode.
C'est une brève explication. Reportez-vous à ici pour comprendre en détail les types de valeurs, les types de référence et les types de valeurs par rapport au type de référence.
Type De Valeur:
-
taille mémoire fixe.
-
stocké dans la mémoire de pile.
-
contient la valeur réelle.
ex. int, char, boolean, etc...
Type De Référence:
-
mémoire non fixée.
-
stocké en mémoire.
-
contient l'adresse mémoire de valeur réelle.
ex. chaîne, tableau, classe, etc...
il n'y a pas une seule différence entre les types de valeurs et les types de référence, il y a beaucoup de petits détails qui sont énoncés explicitement par la norme et certains d'entre eux ne sont pas faciles à comprendre, en particulier pour les débutants.
voir ECMA standard 33, Common Language Infrastructure (CLI) . Le CLI est également normalisé par L'ISO. Je fournirais une référence mais pour ECMA nous devons télécharger un PDF et ce lien dépend sur le numéro de version. Les normes ISO coûtent cher.
une différence est que les types de valeur peuvent être encadrés mais les types de référence ne peuvent généralement pas l'être. Il y a des exceptions, mais elles sont assez techniques.
Les types de valeursne peuvent pas avoir de constructeurs ou de finaliseurs d'instance sans paramètres et ils ne peuvent pas se référer à eux-mêmes. Se référer à eux-mêmes signifie par exemple que s'il y a un type de valeur noeud alors un membre de noeud ne peut pas être un noeud . Je pense qu'il y a d'autres exigences/limites dans les spécifications, mais si c'est le cas, elles ne sont pas rassemblées en un seul endroit.