Список передан ref-помогите мне объяснить это поведение


взгляните на следующую программу:

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;
    }
}

я предположил, что myList прошел бы мимо ref и вывода

3
4

список действительно "передается по ссылке", но только

7 78

7 ответов:

передачи ссылка на список, а как не передача списка переменных по ссылке - поэтому, когда вы звоните ChangeList the значение переменной (т. е. ссылка - думаю, "указатель") копируется - и изменения в значение параметра внутри ChangeListне видели TestMethod.

попробуй:

private void ChangeList(ref List<int> myList) {...}
...
ChangeList(ref myList);
мимо ссылка на локальная переменнаяmyRef (как заявлено в TestMethod); Теперь, если вы переназначите параметр внутри ChangeList вы также переназначение переменной внутриTestMethod.

первоначально он может быть представлен графически следующим образом:

Init states

затем применяется сортировка myList.Sort(); Sort collection

наконец, когда вы сделали: myList' = myList2, вы потеряли один из ссылки, но не оригинал и коллекция осталась отсортированной.

Lost reference

если вы используете ссылки (ref), то myList' и myList станет таким же (только одна ссылка).

Примечание: я использую myList' представлять параметр, который вы используете в ChangeList (потому что вы дали то же имя, что и оригинал)

вот простой способ понять это

  • ваш список-это объект, созданный в куче. Переменная myList - Это ссылка на этот объект.

  • в C# вы никогда не передаете объекты, вы передаете их ссылки по значению.

  • при доступе к объекту списка через переданную ссылку в ChangeList (например, при сортировке) исходный список изменяется.

  • назначение на ChangeList метод сделан к значению ссылки, следовательно никакие изменения не сделаны к первоначальному списку (все еще на куче но не ссылаются на переменную метода больше).

этой ссылка поможет вам в понимании пройти по ссылке в C#. В принципе, когда объект ссылочного типа передается по значению методу, только методы, доступные на этом объекте, могут изменять содержимое объекта.

список.метод sort () изменяет содержимое списка, но если вы назначаете какой-либо другой объект той же переменной, это назначение является локальным для этого метода. Поэтому мой список остается неизменным.

Если мы передаем объект ссылочный тип с помощью ключевого слова ref, то мы можем назначить какой-то другой объект той же переменной и что изменяет весь объект сам по себе.

C# просто делает мелкую копию, когда она проходит по значению, если объект, о котором идет речь, не выполняет ICloneable (который, видимо,List класса нет).

это означает, что он копирует List сам, но ссылки на объекты внутри списка остаются теми же; то есть указатели продолжают ссылаться на те же объекты, что и исходный List.

если вы измените значения вещей ваш новый List ссылки, изменить оригинал List также (поскольку он ссылается на те же объекты). Однако вы тогда измените то, что myList ссылки полностью, на новый List и теперь только оригинал List ссылается на эти числа.

читать Передача Параметров Ссылочного Типа С эта статья MSDN о "передаче параметров" для получения дополнительной информации.

" как клонировать общий список в C#" из StackOverflow рассказывает о том, как чтобы сделать глубокую копию списка.

хотя я согласен с тем, что сказано выше. У меня другой взгляд на этот код. в основном вы назначаете новый список локальной переменной myList, а не глобальной. если вы измените подпись ChangeList (List myList) на private void ChangeList (), вы увидите результат 3, 4.

вот мои рассуждения... Даже если список передается по ссылке, думайте об этом как о передаче переменной указателя по значению Когда вы называете группу(мой список) ты мимо указатель на (глобальный) myList. Теперь это хранится в переменной (local)myList. Итак, теперь ваш (локальный)myList и (глобальный) myList указывают на один и тот же список. Теперь вы делаете сортировку => это работает, потому что (локальный)myList ссылается на исходный (глобальный)myList Затем вы создаете новый список и назначаете указатель на этот ваш (локальный)myList. Но как только функция выходит (локальная)переменная myList уничтожается. ХТ

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;
    }
}

использовать ref ключевое слово.

посмотрите на окончательную ссылку здесь чтобы понять параметры передачи.
Чтобы быть конкретным, посмотрите на этой, чтобы понять поведение кода.

EDIT:Sort работает на той же ссылке (которая передается по значению) и, следовательно, значения упорядочены. Однако назначение нового экземпляра параметру не будет работать, потому что параметр передается по значению, если вы не поместите ref.

положить ref позволяет изменить указатель на ссылку на новый экземпляр List в вашем случае. Без ref, вы можете работать с существующим параметром, но не можете заставить его указать на что-то еще.