Взгляните на следующую программу:
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
Список действительно "передается по ссылке", но действует только sort
функция. Следующее утверждение myList = myList2;
не действует.
Итак, на самом деле результат:
10
50
100
Вы можете помочь мне объяснить такое поведение? Если действительно myList
не передается ссылка (как следует из того myList = myList2
, что она не myList.Sort()
вступает в силу ), как она вступает в силу?
Я предполагал, что даже этот оператор не вступит в силу, а результат будет:
100
50
10
c#
list
pass-by-reference
нмдр
источник
источник
ChangeList
бы вернуть,List<int>
а не быть,void
если он фактически создает новый список.Ответы:
Вы передаете ссылку на список , но ваш не передавая список переменных по ссылке - так что, когда вы звоните
ChangeList
в значение переменной (то есть ссылка - думаю , «указатель») копируется - и изменения в значению параметр внутриChangeList
не виденTestMethod
.пытаться:
Затем он передает ссылку на локальную переменную
myRef
(как объявлено вTestMethod
); теперь, если вы переназначаете параметр внутри,ChangeList
вы также переназначаете переменную внутриTestMethod
.источник
ChangeList
, только ссылка копируется - это тот же самый объект. Если вы каким-то образом измените объект, все, что имеет ссылку на этот объект, увидит изменение.Изначально это можно представить графически следующим образом:
Затем применяется сортировка
myList.Sort();
Наконец, когда вы сделали:,
myList' = myList2
вы потеряли одну из ссылок, но не оригинал, и коллекция осталась отсортированной.Если вы используете by reference (
ref
), тогдаmyList'
иmyList
станет таким же (только одна ссылка).Примечание: я использую
myList'
для представления параметра, который вы используетеChangeList
(потому что вы дали то же имя, что и оригинал)источник
Вот простой способ понять это
Ваш список - это объект, созданный в куче. Переменная
myList
- это ссылка на этот объект.В C # вы никогда не передаете объекты, вы передаете их ссылки по значению.
Когда вы обращаетесь к объекту списка через переданную ссылку
ChangeList
(например, при сортировке), исходный список изменяется.Присваивание
ChangeList
методу выполняется для значения ссылки, следовательно, в исходный список не вносятся изменения (все еще находится в куче, но больше не упоминается в переменной метода).источник
Эта ссылка поможет вам понять переход по ссылке в C #. По сути, когда объект ссылочного типа передается по значению методу, только методы, доступные для этого объекта, могут изменять содержимое объекта.
Например, метод List.sort () изменяет содержимое списка, но если вы назначаете какой-либо другой объект той же переменной, это назначение является локальным для этого метода. Поэтому myList остается неизменным.
Если мы передаем объект ссылочного типа с помощью ключевого слова ref, тогда мы можем назначить какой-либо другой объект той же переменной, и это изменит сам объект.
(Изменить: это обновленная версия документации по ссылке выше.)
источник
C # просто выполняет неглубокую копию при передаче по значению, если только рассматриваемый объект не выполняется
ICloneable
(что, очевидно,List
класс не выполняет).Это означает, что он копирует
List
себя, но ссылки на объекты внутри списка остаются прежними; то есть указатели продолжают ссылаться на те же объекты, что и оригиналList
.Если вы измените значения вещей, которые вы используете в новых
List
ссылках, вы также измените исходныйList
(поскольку он ссылается на те же объекты). Однако затем выmyList
полностью меняете ссылки на новыеList
, и теперь только оригиналList
ссылается на эти целые числа.Прочтите раздел «Передача параметров ссылочного типа » этой статьи MSDN «Передача параметров» для получения дополнительной информации.
«Как клонировать общий список на C #» из StackOverflow рассказывает о том, как сделать полную копию списка.
источник
Хотя я согласен с тем, что все сказали выше. У меня другой взгляд на этот код. В основном вы назначаете новый список локальной переменной myList, а не глобальной. если вы измените подпись ChangeList (List myList) на private void ChangeList (), вы увидите результат 3, 4.
Вот мои рассуждения ... Даже если список передается по ссылке, думайте об этом как о передаче переменной-указателя по значению. Когда вы вызываете ChangeList (myList), вы передаете указатель на (Global) myList. Теперь это хранится в (локальной) переменной myList. Итак, теперь ваш (локальный) myList и (глобальный) myList указывают на один и тот же список. Теперь вы выполняете sort => это работает, потому что (локальный) myList ссылается на исходный (глобальный) myList. Затем вы создаете новый список и назначаете указатель на этот ваш (локальный) myList. Но как только функция завершает работу, (локальная) переменная myList уничтожается. HTH
источник
Используйте
ref
ключевое слово.Посмотрите полную ссылку здесь, чтобы понять передаваемые параметры.
Чтобы быть конкретным, посмотрите на это , чтобы понять поведение кода.
EDIT:
Sort
работает с той же ссылкой (которая передается по значению), и, следовательно, значения упорядочены. Однако присвоение нового экземпляра параметру не сработает, поскольку параметр передается по значению, если вы не укажетеref
.Помещение
ref
позволяет вам изменить указатель на ссылку на новый экземплярList
в вашем случае. Без негоref
вы можете работать с существующим параметром, но не можете заставить его указывать на что-то другое.источник
Для объекта ссылочного типа выделены две части памяти. Один в стеке и один в куче. Часть в стеке (также известная как указатель) содержит ссылку на часть в куче, где хранятся фактические значения.
Когда ключевое слово ref не используется, создается только копия части в стеке и передается методу - ссылка на ту же часть в куче. Поэтому, если вы что-то измените в части кучи, эти изменения останутся. Если вы измените скопированный указатель - назначив его для ссылки на другое место в куче - это не повлияет на указатель источника вне метода.
источник