Quand utiliser le mot clé C # ref est-il une bonne idée?

Plus je vois d’arbitrage utilisé dans le code de production, plus je rencontre d’abus et de douleur. Je suis venu à haïr ce mot-clé, parce que d’un sharepoint vue de la construction d’un cadre, il semble idiot. Quand serait-il judicieux de communiquer aux utilisateurs de votre code la possibilité de modifier une référence / valeur d’object en dessous?

En revanche, j’aime les mots-clés et encore plus quand aucun mot-clé n’est utilisé, dans les deux cas, en raison des garanties qui vous sont données lorsque vous les utilisez. Par contre, la référence ne donne aucune garantie, sauf que vous serez obligé d’initialiser le paramètre avant de le transmettre, même si rien ne peut être changé à ce sujet.

Je ne suis pas un développeur sage cependant; Je suis sûr que ses utilisations sont pratiquement applicables. J’aimerais juste savoir ce qu’ils sont.

Le Framework Design Guidelines (un livre de Krzysztof Cwalina et Brad Abrams) recommande d’éviter les parameters ref et out .

ÉVITER d’ utiliser out parameters out ou ref .

L’utilisation de parameters out ou ref nécessite une expérience des pointeurs, de la compréhension des types de valeur et des types de référence et des méthodes de traitement avec plusieurs valeurs de retour. En outre, la différence entre out parameters out et ref n’est pas bien comprise. Les architectes de cadre conçus pour un public général ne doivent pas s’attendre à ce que les utilisateurs maîsortingsent le travail avec out parameters out ou ref .

Les directives de conception du cadre citent la méthode canonique Swap comme une exception valide:

 void Swap(ref T obj1, ref T obj2) { T temp = obj1; obj1 = obj2; obj2 = temp; } 

mais en même temps un commentaire remarque

Le swap revient toujours dans ces discussions, mais je n’ai pas écrit de code qui nécessitait une méthode de swap depuis le collège. À moins que vous n’ayez une très bonne raison, évitez out renvois.

La plupart des méthodes Interlocked utilisent des parameters ref pour (je suis sûr que vous êtes d’accord) une bonne raison.

J’essaie de l’éviter sur les API publiques, mais il a certainement des utilisations. Les types de valeurs mutables sont importants, en particulier dans des domaines tels que CF (où les structures mutables sont plus courantes, en raison des exigences de la plate-forme). Cependant, le moment le plus couramment utilisé est le refactoring de parties d’un algorithme complexe en quelques méthodes, lorsqu’un object state est excessif et que je dois transmettre plusieurs valeurs autour de:

c’est à dire

 var x = ..... var y = ..... // some local code... var z = DoSomethingSpecific(ref x, ref y); // needs and updates x/y // more local code... 

etc. Où DoSomethingSpecific est une méthode privée, vient de déménager pour que la responsabilité de la méthode rest gérable.

Chaque fois que vous souhaitez modifier la valeur d’un type de valeur – cela se produit souvent dans les cas où vous souhaitez mettre à jour efficacement une paire de valeurs liées (c’est-à-dire qu’au lieu de renvoyer une structure contenant deux ints, vous passez (ref int x, ref int y))

Peut-être que lorsque vous avez une structure (qui est un type de valeur):

 struct Foo { int i; public void Test() { i++; } } static void update(ref Foo foo) { foo.Test(); } 

et

 Foo b = new Foo(); update(ref b); 

Ici, vous utiliseriez deux parameters avec:

 static void update(Foo foo, out Foo outFoo) //Yes I know you could return one foo instead of a out but look below { foo.Test(); outFoo = foo; } 

En imageant la méthode ayant plus d’un Foo vous obtiendriez deux fois les parameters avec out par rapport à ref . Une alternative consiste à renvoyer un N-tuple. Je n’ai pas d’exemple concret pour savoir quand utiliser ce genre de choses.

Ajouter: Différentes méthodes .TryParse auraient également pu éviter si elles retournaient Nullable place, ce qui est essentiellement un tuple de boolean * T

C’est utile lorsque vous avez besoin d’algorithmes en place efficaces sur les bignums.

De manière hypothétique, je suppose que vous pourriez utiliser beaucoup d’arguments ref / out si vous vouliez imiter l’architecture d’un logiciel procédural plus ancien, par exemple d’anciens moteurs de jeu, etc. J’ai scanné le code source de l’un, je pense que c’était Duke Nukem 3D, et il est procédural avec beaucoup de sous-routines modifiant les variables en place et presque aucune fonction. De toute évidence, il est peu probable que vous programmiez ainsi pour une application de production réelle à moins d’avoir un objective précis en tête.

Que diriez-vous si on souhaite passer un tableau à une fonction qui pourrait ou non changer sa taille et lui faire autre chose. Souvent, on encapsule le tableau dans un autre object, mais si l’on souhaite gérer le tableau directement en passant par référence, cela semble l’approche la plus naturelle.

J’utilise assez souvent les ref. Pensez simplement aux fonctions avec plusieurs valeurs de retour. Cela n’a pas de sens de créer un object de retour (object d’assistance) ou même d’utiliser des hashtables à cette fin.

Exemple:

  getTreeNodeValues(ref selectedValue, ref selectedText); 

Modifier:

Il vaut mieux utiliser ici – commenté.

  getTreeNodeValues(out selectedValue, out selectedText); 

Je l’utilise pour traiter des objects:

 MyCar car = new MyCar { Name="TestCar"; Wieght=1000; } UpdateWeight(ref car, 2000); 

Un autre exemple utile en plus d’échanger <> est le suivant:

 Prompter.getSsortingng("Name ? ", ref firstName); Prompter.getSsortingng("Lastname ? ", ref lastName); Prompter.getSsortingng("Birthday ? ", ref firstName); Prompter.getInt("Id ? ", ref id); Prompter.getChar("Id type:  \n? ", ref c); public static class Prompter { public static void getKey(ssortingng msg, ref ssortingng key) { Console.Write(msg); ConsoleKeyInfo cki = Console.ReadKey(); ssortingng k = cki.Key.ToSsortingng(); if (k.Length == 1) key = k; } public static void getChar(ssortingng msg, ref char key) { Console.Write(msg); key = Console.ReadKey().KeyChar; Console.WriteLine(); } public static void getSsortingng(ssortingng msg, ref ssortingng s) { Console.Write(msg); ssortingng input = Console.ReadLine(); if (input.Length != 0) s = input; } public static void getInt(ssortingng msg, ref int i) { int result; ssortingng s; Console.Write(msg); s = Console.ReadLine(); int.TryParse(s, out result); if (result != 0) i = result; } // not implemented yet public static ssortingng getDate(ssortingng msg) { // I should use DateTime.ParseExact(dateSsortingng, format, provider); throw new NotImplementedException(); } } 

Utilisez ici ce n’est pas une option