132 votes

Liste passée par réf - aidez-moi à expliquer ce comportement

Regardez le programme suivant:

class Test
{
    List<int> myList = new List<int>();

    public void TestMethod()
    {

        myList.Add(100);
        myList.Add(50);
        myList.Add(10);

        ChangeList(myList);

        foreach (int i in myList)
        {
            Console.WriteLine(i);
        }
    }

    private void ChangeList(List<int> myList)
    {
        myList.Sort();

        List<int> myList2 = new List<int>();
        myList2.Add(3);
        myList2.Add(4);

        myList = myList2;
    }
}

Je suppose myList serait passé à côté de ref, et la sortie

3
4

La liste est en effet "adoptée par le ref", mais seulement l' sort fonction prend effet. La déclaration suivante myList = myList2; n'a pas d'effet.

Si la sortie est en fait:

10
50
100

Pouvez-vous m'aider à expliquer ce comportement? Si, en effet, myList n'est pas passé par ref (tel qu'il apparaît à partir de myList = myList2 ne s'applique pas), comment est - myList.Sort() prendre effet?

J'ai été en supposant même que la déclaration ne prennent pas effet et la sortie:

100
50
10

253voto

Jaider Points 2366

Ce que vous avez fait, peut être représenté graphiquement comme ceci:

enter image description here

Et quand vous l'avez fait: myList' = myList2, vous avez perdu la copie, mais pas l'original. enter image description here

Si vous utilisez par référence (ref) alors myList' sera le même que l' myList et il fonctionnera comme prévu.

Remarque: j'utilise myList' pour représenter le paramètre que vous utilisez en ChangeList (parce que vous avez donné le même nom que l'original)

126voto

Marc Gravell Points 482669

Vous êtes de passage d'une référence à la liste, mais vos n'êtes pas en passant la liste des variables par référence - de sorte que lorsque vous appelez ChangeList de la valeur de la variable (c'est à dire la référence - penser "pointeur") est copié, et les changements de la valeur du paramètre à l'intérieur d' ChangeList ne sont pas vu par TestMethod.

essayez:

private void ChangeList(ref List<int> myList) {...}
...
ChangeList(ref myList);

Cela passe ensuite une référence à la locale de la variable myRef (comme l'a déclaré en TestMethod); maintenant, si vous réaffectez le paramètre à l'intérieur d' ChangeList vous sont également de la réattribution de la variable à l'intérieur d' TestMethod.

23voto

Unmesh Kondolikar Points 4744

Voici un moyen facile de le comprendre

  • Votre Liste est un objet créé sur le tas. La variable myList est un référence à cet objet.

  • En C# vous de ne jamais passer des objets, vous passez de leurs références en valeur.

  • Lorsque vous accédez à la liste de l'objet par le passé de référence dans ChangeList (alors que le tri, par exemple), la liste d'origine est modifié.

  • L'affectation sur l' ChangeList méthode est effectuée à la valeur de la référence, donc aucune modification n'est apportée à la liste d'origine (toujours sur le tas, mais qui n'est pas référencée sur la méthode de la variable plus).

13voto

Shekhar Points 2342

ce lien vous aidera dans la compréhension de passage par référence en C#. En gros,quand un objet de type de référence est passé par valeur à une méthode, seules les méthodes qui sont disponibles sur cet objet peut modifier le contenu de l'objet.

Par exemple la Liste.méthode sort() les changements de contenu de Liste, mais si vous affectez un autre objet à la même variable, que la cession est locale à cette méthode. C'est pourquoi maliste reste inchangé.

Si nous passons à l'objet de référence à l'aide de mot-clé ref ensuite, nous pouvons attribuer un autre objet à la même variable, et que les changements totalité de l'objet lui-même.

4voto

sandeep Points 21

Alors que je suis d'accord avec ce que tout le monde l'a dit ci-dessus. J'ai une approche différente de ce code. Fondamentalement, vous êtes à l'attribution de la nouvelle liste de la variable locale maliste pas le mondial. si vous modifiez la signature de la liste de Modifications(Liste maliste) pour private void liste de Modifications() vous verrez le résultat de 3, 4.

Voici mon raisonnement... Même si la liste est passée par référence, il pense que le passage d'un pointeur de variable par valeur Lorsque vous appelez la liste de Modifications(maliste) vous êtes en passant le pointeur de (Global)maliste. Maintenant, c'est stockée dans l' (local)maliste variable. Alors maintenant, vos (local)maliste et (global)maliste pointent vers la même liste. Maintenant, vous faites un tri => cela fonctionne parce que (local)maliste référence à l'original (global)maliste Ensuite, vous devez créer une nouvelle liste et attribuer le pointeur pour que votre (local)maliste. Mais dès que la fonction se termine le (local)maliste variable est détruite. HTH

class Test
{
    List<int> myList = new List<int>();
    public void TestMethod()
    {

        myList.Add(100);
        myList.Add(50);
        myList.Add(10);

        ChangeList();

        foreach (int i in myList)
        {
            Console.WriteLine(i);
        }
    }

    private void ChangeList()
    {
        myList.Sort();

        List<int> myList2 = new List<int>();
        myList2.Add(3);
        myList2.Add(4);

        myList = myList2;
    }
}

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