342 votes

Pourquoi utiliser le mot clé "ref" pour transmettre un objet ?

Si je passe un objet à une méthode, pourquoi devrais-je utiliser le mot-clé ref ? N'est-ce pas le comportement par défaut de toute façon ?

Par exemple :

class Program
{
    static void Main(string[] args)
    {
        TestRef t = new TestRef();
        t.Something = "Foo";

        DoSomething(t);
        Console.WriteLine(t.Something);
    }

    static public void DoSomething(TestRef t)
    {
        t.Something = "Bar";
    }
}

public class TestRef
{
    public string Something { get; set; }
}

Le résultat est "Bar", ce qui signifie que l'objet a été passé comme une référence.

348voto

Scott Langham Points 17447

Passez un ref si vous voulez changer 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 une string . Vous ne pouvez pas modifier la valeur d'un string une fois qu'il a été créé. Mais en utilisant un ref vous pouvez créer une fonction qui remplace la chaîne par une autre dont la valeur est différente.

Ce n'est pas une bonne idée d'utiliser ref à moins que cela ne soit nécessaire. Utilisation de 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é.

De même, 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 paramètre ref est utilisé, vous avez une référence à une référence. Cela vous permet de faire des choses comme celles décrites dans l'exemple donné ci-dessus. Mais, lorsque le type de paramètre est une valeur primitive (par ex. int ), alors si ce paramètre est affecté à l'intérieur de la méthode, la valeur de l'argument qui a été passé 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;
}

98voto

Jon Skeet Points 692016

Vous devez faire la distinction entre "passer une référence par valeur" et "passer un paramètre/argument par référence".

J'ai écrit un article assez long sur le sujet pour éviter d'avoir à écrire soigneusement chaque fois que ce sujet est abordé dans les newsgroups

1 votes

J'ai rencontré ce problème lors de la mise à niveau de VB6 en code C# .Net. Il y a des signatures de fonctions/méthodes qui prennent des paramètres ref, out et plain. Alors, comment pouvons-nous mieux distinguer la différence entre un paramètre simple et un ref ?

2 votes

@bonCodigo : Je ne suis pas sûr de ce que vous entendez par "mieux distinguer" - cela fait partie de la signature, et vous devez le spécifier. ref à l'emplacement de l'appel également... où voulez-vous qu'il soit distingué ? 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).

0 votes

Je ne sais pas pourquoi visual studio ne montre toujours pas explicitement ce qui est passé

65voto

Ricky AH Points 2366

Dans .NET, lorsque vous passez un paramètre à une méthode, une copie est créée. Dans les types de valeurs, cela signifie que toute modification apportée à la valeur se situe dans la portée de la méthode et est perdue lorsque vous quittez la méthode.

Lorsque vous passez 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, celui-ci est modifié. Mais si vous modifiez la référence elle-même - il ne faut pas oublier qu'il s'agit d'une copie - 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, elle est donc perdue :

public void Method1(object obj) {   
 obj = new Object(); 
}

public void Method2(object obj) {  
 obj = _privateObject; 
}

Les méthodes ci-dessus ne modifient pas l'objet original.

Une petite modification de votre exemple

 using System;

    class Program
        {
            static void Main(string[] args)
            {
                TestRef t = new TestRef();
                t.Something = "Foo";

                DoSomething(t);
                Console.WriteLine(t.Something);

            }

            static public void DoSomething(TestRef t)
            {
                t = new TestRef();
                t.Something = "Bar";
            }
        }

    public class TestRef
    {
    private string s;
        public string Something 
        { 
            get {return s;} 
            set { s = value; }
        }
    }

10 votes

J'aime mieux cette réponse que la réponse acceptée. Elle explique plus clairement ce qui se passe lors du passage d'une variable de type référence avec le mot-clé ref. Je vous remercie !

18voto

Ferruccio Points 51508

Puisque TestRef est une classe (qui sont des objets de référence), vous pouvez modifier le contenu de t sans le passer comme une référence. Cependant, si vous passez t comme une référence, TestRef peut changer ce à quoi l'original t fait référence, c'est-à-dire le faire pointer vers un objet différent.

17voto

Rinat Abdullin Points 13520

Con ref vous pouvez écrire :

static public void DoSomething(ref TestRef t)
{
    t = new TestRef();
}

Et t sera modifié après la fin de la méthode.

0 votes

Et si ref n'a pas été spécifié, alors t est le même objet avec toutes les propriétés remises à leur valeur initiale. En ce qui concerne l'appelant, l'argument passé aura toujours des propriétés réinitialisées. Quel est l'intérêt de faire cela ?

0 votes

J'ai obtenu une réponse à ma question : pourquoi utiliser la référence quand on peut modifier l'objet dans une autre méthode, même sans référence ?

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X