Passez un ref
si vous voulez changer ce qu'est l'objet:
TestRef t = new TestRef();
t.Something = "Foo";
DoSomething(ref t);
void DoSomething(ref TestRef t)
{
t = new TestRef();
t.Something = "Not just a changed t, but a completely different TestRef object";
}
Après avoir appelé DoSomething, t
ne fait pas référence à l'original new TestRef
, mais fait référence à un objet complètement différent.
Cela peut également être utile si vous souhaitez modifier la valeur d'un objet immuable, par exemple a string
. Vous ne pouvez pas modifier la valeur de a une string
fois qu'il a été créé. Mais en utilisant un ref
, vous pouvez créer une fonction qui change la chaîne pour une autre qui a une valeur différente.
Edit: Comme d'autres l'ont mentionné. Ce n'est pas une bonne idée d'utiliser à ref
moins que cela ne soit nécessaire. L'utilisation ref
donne à la méthode la liberté de changer l'argument pour autre chose, les appelants de la méthode devront être codés pour s'assurer qu'ils gèrent cette possibilité.
En outre, lorsque le type de paramètre est un objet, les variables d'objet agissent toujours comme des références à l'objet. Cela signifie que lorsque le ref
mot clé est utilisé, vous avez une référence à une référence. Cela vous permet de faire les choses comme décrit dans l'exemple donné ci-dessus. Mais, lorsque le type de paramètre est une valeur primitive (par exemple int
), si ce paramètre est affecté à l'intérieur de la méthode, la valeur de l'argument transmis sera modifiée après le retour de la méthode:
int x = 1;
Change(ref x);
Debug.Assert(x == 5);
WillNotChange(x);
Debug.Assert(x == 5); // Note: x doesn't become 10
void Change(ref int x)
{
x = 5;
}
void WillNotChange(int x)
{
x = 10;
}
ref
sur le site de l'appel ... où voudriez-vous le distinguer? La sémantique est également assez claire, mais doit être exprimée avec soin (plutôt que «les objets sont passés par référence», ce qui est la simplification excessive courante).Dans .NET lorsque vous transmettez un paramètre à une méthode, une copie est créée. Dans les types de valeur signifie que toute modification que vous apportez à la valeur est à la portée de la méthode et est perdue lorsque vous quittez la méthode.
Lors du passage d'un type de référence, une copie est également effectuée, mais il s'agit d'une copie d'une référence, c'est-à-dire que vous avez maintenant DEUX références en mémoire pour le même objet. Donc, si vous utilisez la référence pour modifier l'objet, il est modifié. Mais si vous modifiez la référence elle-même - nous devons nous rappeler que c'est une copie - alors toutes les modifications sont également perdues à la sortie de la méthode.
Comme on l'a déjà dit, une affectation est une modification de la référence, donc se perd:
Les méthodes ci-dessus ne modifient pas l'objet d'origine.
Une petite modification de votre exemple
la source
Puisque TestRef est une classe (qui sont des objets de référence), vous pouvez changer le contenu à l'intérieur de t sans le passer comme référence. Cependant, si vous passez t comme référence, TestRef peut changer ce à quoi le t d'origine fait référence. c'est-à-dire le faire pointer vers un objet différent.
la source
Avec
ref
vous pouvez écrire:Et t sera modifié une fois la méthode terminée.
la source
Considérez les variables (par exemple
foo
) des types de référence (par exempleList<T>
) comme contenant des identifiants d'objet de la forme "Objet # 24601". Supposons que l'instructionfoo = new List<int> {1,5,7,9};
provoquefoo
le maintien de "Objet # 24601" (une liste avec quatre éléments). Ensuite, l'appelfoo.Length
demandera à l'objet # 24601 sa longueur, et il répondra 4, doncfoo.Length
égal à 4.Si
foo
est passé à une méthode sans l'utiliserref
, cette méthode peut apporter des modifications à l'objet n ° 24601. À la suite de ces changements, il sefoo.Length
peut qu'ils ne soient plus égaux à 4. La méthode elle-même, cependant, ne pourra pas changerfoo
, qui continuera à contenir "Objet # 24601".Le passage
foo
enref
paramètre permettra à la méthode appelée d'apporter des modifications non seulement à l'objet # 24601, mais également àfoo
elle-même. La méthode peut créer un nouvel objet # 8675309 et stocker une référence à celui-ci dansfoo
. Si tel est le cas,foo
ne contiendrait plus "Objet # 24601", mais plutôt "Objet # 8675309".En pratique, les variables de type référence ne contiennent pas de chaînes de la forme "Objet # 8675309"; ils ne contiennent même rien qui puisse être converti de manière significative en nombre. Même si chaque variable de type référence contiendra un motif binaire, il n'y a pas de relation fixe entre les motifs binaires stockés dans ces variables et les objets qu'ils identifient. Il n'y a aucun moyen que le code puisse extraire des informations d'un objet ou d'une référence à celui-ci, et déterminer plus tard si une autre référence a identifié le même objet, à moins que le code ne contienne ou ne connaissait une référence qui a identifié l'objet d'origine.
la source
C'est comme passer un pointeur à un pointeur en C. Dans .NET, cela vous permettra de changer ce à quoi le T d'origine fait référence, personnellement, bien que je pense que si vous le faites dans .NET, vous avez probablement un problème de conception!
la source
En utilisant le
ref
mot - clé avec des types de référence, vous transmettez effectivement une référence à la référence. À bien des égards, c'est la même chose que d'utiliser leout
mot - clé, mais avec la différence mineure qu'il n'y a aucune garantie que la méthode affectera réellement quelque chose auref
paramètre 'ed.la source
ref
imite (ou se comporte) comme une zone globale juste pour deux étendues:la source
Si vous passez une valeur, cependant, les choses sont différentes. Vous pouvez forcer une valeur à passer par référence. Cela vous permet de passer un entier à une méthode, par exemple, et de demander à la méthode de modifier l'entier en votre nom.
la source
Ref indique si la fonction peut mettre la main sur l'objet lui-même, ou seulement sur sa valeur.
Le passage par référence n'est pas lié à une langue; c'est une stratégie de liaison de paramètres à côté de pass-by-value, pass by name, pass by need etc ...
Un sidenote: le nom de classe
TestRef
est un mauvais choix hideux dans ce contexte;).la source