Quelle est l’utilisation de «ref» pour les variables de type référence dans C #?

Je comprends que si je passe un type de valeur ( int , struct , etc.) en tant que paramètre (sans le mot-clé ref ), une copie de cette variable est transmise à la méthode, mais si j’utilise le mot-clé ref une référence à cette la variable est passée, pas une nouvelle.

Mais avec les types de référence, comme les classes, même sans le mot-clé ref , une référence est transmise à la méthode, pas une copie. Alors, comment utiliser le mot-clé ref avec les types de référence?


Prends pour exemple:

 var x = new Foo(); 

Quelle est la différence entre les éléments suivants?

 void Bar(Foo y) { y.Name = "2"; } 

et

 void Bar(ref Foo y) { y.Name = "2"; } 

Vous pouvez changer ce que foo pointe en utilisant y :

 Foo foo = new Foo("1"); void Bar(ref Foo y) { y = new Foo("2"); } Bar(ref foo); // foo.Name == "2" 

Il y a des cas où vous souhaitez modifier la référence réelle et non l’object pointé:

 void Swap(ref T x, ref T y) { T t = x; x = y; y = t; } var test = new[] { "0", "1" }; Swap(ref test[0], ref test[1]); 

Jon Skeet a écrit un excellent article sur le passage des parameters en C #. Il détaille clairement le comportement exact et l’utilisation des parameters de transmission par valeur, par référence ( ref ) et par sortie ( out ).

Voici une citation importante de cette page en relation avec les parameters ref :

Les parameters de référence ne transmettent pas les valeurs des variables utilisées dans l’invocation de membre de la fonction: ils utilisent les variables elles-mêmes. Plutôt que de créer un nouvel emplacement de stockage pour la variable dans la déclaration du membre de la fonction, le même emplacement de stockage est utilisé, de sorte que la valeur de la variable dans le membre de la fonction et la valeur du paramètre de référence seront toujours les mêmes. Les parameters de référence ont besoin du modificateur ref dans le cadre de la déclaration et de l’invocation – cela signifie qu’il est toujours clair lorsque vous transmettez quelque chose par référence.

Très bien expliqué ici: http://msdn.microsoft.com/en-us/library/s6938f28.aspx

Résumé de l’article:

Une variable de type référence ne contient pas directement ses données; il contient une référence à ses données. Lorsque vous transmettez un paramètre de type référence par valeur, il est possible de modifier les données pointées par la référence, telles que la valeur d’un membre de classe. Cependant, vous ne pouvez pas modifier la valeur de la référence elle-même; En d’autres termes, vous ne pouvez pas utiliser la même référence pour allouer de la mémoire à une nouvelle classe et la faire persister en dehors du bloc. Pour cela, transmettez le paramètre à l’aide du mot clé ref ou out.

Lorsque vous transmettez un type de référence avec le mot-clé ref, vous transmettez la référence par référence et la méthode que vous appelez peut affecter une nouvelle valeur au paramètre. Ce changement se propagera à la scope d’appel. Sans ref, la référence est passée par valeur et cela ne se produit pas.

C # a aussi le mot clé ‘out’ qui ressemble beaucoup à ref, sauf qu’avec ‘ref’, les arguments doivent être initialisés avant d’appeler la méthode, et avec ‘out’ vous devez assigner une valeur dans la méthode de réception.

Il vous permet de modifier la référence passée.

 void Bar() { var y = new Foo(); Baz(ref y); } void Baz(ref Foo y) { y.Name = "2"; // Overwrite the reference y = new Foo(); } 

Vous pouvez également utiliser si vous ne vous souciez pas de la référence transmise dans:

 void Bar() { var y = new Foo(); Baz(out y); } void Baz(out Foo y) { // Return a new reference y = new Foo(); } 

Un autre tas de code

 class O { public int prop = 0; } class Program { static void Main(ssortingng[] args) { O o1 = new O(); o1.prop = 1; O o2 = new O(); o2.prop = 2; o1modifier(o1); o2modifier(ref o2); Console.WriteLine("1 : " + o1.prop.ToSsortingng()); Console.WriteLine("2 : " + o2.prop.ToSsortingng()); Console.ReadLine(); } static void o1modifier(O o) { o = new O(); o.prop = 3; } static void o2modifier(ref O o) { o = new O(); o.prop = 4; } } 

En plus des réponses existantes:

Comme vous avez demandé la différence entre les deux méthodes: Il n’y a pas de variance co (ntra) lorsque vous utilisez ref ou out :

 class Foo { } class FooBar : Foo { } static void Bar(Foo foo) { } static void Bar(ref Foo foo) { foo = new Foo(); } void Main() { Foo foo = null; Bar(foo); // OK Bar(ref foo); // OK FooBar fooBar = null; Bar(fooBar); // OK (covariance) Bar(ref fooBar); // comstack time error } 

Un paramètre dans une méthode semble toujours transmettre une copie, la question est une copie de quoi. Une copie est faite par un constructeur de copie pour un object et comme toutes les variables sont Object en C #, je pense que c’est le cas pour toutes. Les variables (objects) sont comme les personnes vivant à certaines adresses. Nous changeons les personnes vivant à ces adresses ou nous pouvons créer plus de références aux personnes vivant à ces adresses dans l’annuaire téléphonique (faire des copies superficielles). Ainsi, plus d’un identifiant peut faire référence à la même adresse. Les types de référence désirent plus d’espace, donc, contrairement aux types de valeur qui sont directement connectés par une flèche à leur identifiant dans la stack, ils ont une valeur pour une autre adresse dans le tas (un plus grand espace à habiter). Cet espace doit être extrait du tas.

Type de valeur: Indentifier (contient la valeur = adresse de la valeur de la stack) —-> Valeur du type de valeur

Type de référence: Identifiant (contient la valeur = adresse de la valeur de la stack) —-> (contient la valeur = adresse de la valeur du tas) —-> Valeur du tas (contient le plus souvent des adresses à d’autres valeurs), imaginez plus de flèches différentes directions vers Array [0], Array [1], array [2]

La seule façon de changer une valeur est de suivre les flèches. Si une flèche est perdue ou modifiée de la même manière, la valeur est inaccessible.

Les variables de référence portent l’adresse d’un endroit à un autre, donc toute mise à jour à n’importe quel endroit se répercutera sur tous les endroits ALORS quelle est l’utilisation de REF. La variable de référence est bonne jusqu’à ce qu’aucune nouvelle mémoire ne soit allouée à la variable de référence transmise dans la méthode. Une fois la mémoire allouée, le changement de valeur ne reflétera pas partout. Pour cette référence vient. Ref est une référence de référence. Ainsi, chaque fois qu’une nouvelle mémoire lui atsortingbue une connaissance, parce qu’elle pointe vers cet emplacement, la valeur peut être partagée par everyOne. Vous pouvez voir l’image pour plus de clarté.

Réf dans la variable de référence