Тип ссылки C # String передан как копия?

Я сомневаюсь, что это относится к ссылочным типам C # "String".

Следующий код:

string s = "lana del rey" 
string d = s;
s = "elvis presley";
Console.Writeline(d);

Почему на выходе нет «элвиса пресли»? Если d указывает на то же место в памяти, что и s?

Не могли бы вы объяснить это?

Более подробное объяснение моего первоначального вопроса:

Все ваши ответы были очень полезными. Этот вопрос пришел ко мне с этим общим образцом кода, который часто используется для объяснения разницы между типами значений и ссылочными типами:

class Rectangle
{
    public double Length { get; set; }
}

struct Point 
{
    public double X, Y;
}

Point p1 = new Point();
p1.X = 10;
p1.Y = 20;
Point p2 = p1;
p2.X = 100;
Console.WriteLine(“p1.X = {0}”, p1.X);

Rectangle rect1 = new Rectangle
{ Length = 10.0, Width = 20.0 };
Rectangle rect2 = rect1;
rect2.Length = 100.0;
Console.WriteLine(“rect1.Length = {0}”,rect1.Length);

В этом случае второй оператор Console.WriteLine выведет: «rect1.Length = 100».

В этом случае класс является ссылочным типом, а структура - типом значения. Как я могу продемонстрировать поведение одного и того же ссылочного типа с помощью строки?

Заранее спасибо.


person Alberto Montellano    schedule 15.01.2014    source источник
comment
Вы задали тот же вопрос несколько минут назад, а затем удалили свой вопрос. Ссылки по теме вам не помогли?   -  person Tim S.    schedule 16.01.2014
comment
Предположим, вы вместо этого сказали int x = 1; int y = x; x = 2; Console.WriteLine(y); Ожидаете ли вы, что y будет 1 или 2? int y = x не означает, что y теперь псевдоним x. Это означает, что текущее значение y изменяется на текущее значение x. Между ними не складывается никаких постоянных отношений. То же самое и с вашими s и d.   -  person Eric Lippert    schedule 16.01.2014
comment
@EricLippert Я думаю, он перепутал ссылку с указателем, как упоминал zerkms.   -  person crush    schedule 16.01.2014
comment
Если у вас есть новый вопрос, вам следует задать новый вопрос, а не редактировать новый вопрос в существующем (и уже отвеченном) вопросе.   -  person Servy    schedule 16.01.2014
comment
Спасибо за отзывы @Servy   -  person Alberto Montellano    schedule 16.01.2014


Ответы (6)


Это не имеет никакого отношения к изменчивости.

string s = "lana del rey" 
string d = s;

Здесь 2 переменные s и d относятся к одному и тому же объекту в памяти.

s = "elvis presley";

здесь, в правой части оператора, новый объект выделяется и инициализируется с помощью "elvis presley" и назначается s. Итак, теперь s относится к другому объекту. И хотя мы не изменили ссылочное значение d - оно по-прежнему ссылается на "lana del rey", как это было изначально.

А теперь аналогия из реальной жизни:

Два человека (A и B) указывают пальцами на здание далеко. Они независимы друг от друга и даже не видят, на что другой указывает. Затем A решает указать на другое здание. Пока они не связаны друг с другом - теперь A указывает на другое здание, а B продолжает указывать на исходное здание (поскольку никто не просил их прекратить это делать)

PS: то, что вы, вероятно, смущаете, - это концепция, лежащая в основе указателя и ссылки. Не уверен, имеет ли смысл объяснять это здесь, так как вы можете запутаться еще больше. Но теперь, по крайней мере, вы можете найти в Google соответствующие ключевые слова.

person zerkms    schedule 15.01.2014
comment
Судя по формулировке и характеру вопроса, автор понял, что s был установлен на ссылку d. Чего он не понимал, так это того, что "elvis presley" создавал новый string экземпляр, а не устанавливал значение экземпляра, на который s ссылается. Вот почему string неизменяемость упоминалась во многих ответах: чтобы проиллюстрировать, почему создается новый string экземпляр. - person crush; 16.01.2014
comment
@crush: Я не понимаю, насколько это актуально - ни одна из строк не была изменена и даже не пыталась: -S - person zerkms; 16.01.2014
comment
@crush: И изменяемые ссылочные типы демонстрируют такое же поведение, не так ли? Ввод x = y, где x - ссылочный тип (изменяемый или нет), никогда не означает изменение объекта, на который ссылается x. - person Aaron; 16.01.2014
comment
Мне кажется, что автор думал, что s = "elvis presley" изменяет экземпляр string, созданный с помощью string s = "lana del rey";. Да, изменяемые ссылочные типы демонстрируют такое же поведение. Но автор не понял, что создается новая справка. Он думал, что просто устанавливает значение существующей ссылки. К такому выводу я пришел, по крайней мере, прочитав способ постановки этого вопроса. В его образце кода казалось очевидным, что он знал, что s = d устанавливает эти две ссылки друг на друга. - person crush; 16.01.2014
comment
@crush: Но автор не понял, что создается новая ссылка --- и создание нового экземпляра все еще не имеет ничего общего с изменчивостью. - person zerkms; 16.01.2014
comment
@zerkms Mutability рассматривался как дополнительное объяснение того, почему s = "elvis presley" не изменял существующий экземпляр, а создавал новый. Так я истолковал замешательство автора. Если бы s = "elvis presley" устанавливал значение экземпляра строки, на который ссылается s, тогда Console.WriteLine(d) выводил бы elvis presley. Однако ваша гипотеза о том, что автор путал указатели и ссылки, имеет больше смысла. - person crush; 16.01.2014
comment
пожалуйста, см. мой отредактированный вопрос или вопрос ниже. - person Alberto Montellano; 16.01.2014

Строки в C # неизменяемы; это означает, что они не могут измениться. Когда вы говорите s = "elvis presley", вы создаете новую строку и присваиваете ее ссылку s; это не влияет на ссылку, сохраненную в d, которая по-прежнему указывает на исходную строку.

person TypeIA    schedule 15.01.2014
comment
Даже для изменяемых типов поведение будет таким же. s - это ссылка, а не указатель. - person zerkms; 16.01.2014
comment
Итак, String похожа на исключение из ссылочного типа? - person Alberto Montellano; 16.01.2014
comment
@AlbertoMontellano: Нет. Есть много-много неизменяемых ссылочных типов (и вы можете создать столько, сколько захотите), в них есть что-то особенное. - person Servy; 16.01.2014
comment
@AlbertoMontellano Не совсем (это исключительный ссылочный тип, но не в том смысле, в котором вы имеете в виду). Каждый раз, когда вы присваиваете переменной ссылочного типа, вы просто меняете объект, на который ссылается эта переменная. Вы не изменяете исходный объект. Исходный объект все еще существует, и другие переменные могут ссылаться на него (в противном случае объект имеет право на сборку мусора). - person TypeIA; 16.01.2014

Строки неизменны. s = "elvis presley" фактически создает новый string и назначает его ссылку на переменную s. Хотя переменная d по-прежнему ссылается на первый string "lana del rey".

person crush    schedule 15.01.2014
comment
в этом случае String ведет себя как тип значения? создание копии стоимости? - person Alberto Montellano; 16.01.2014
comment
@AlbertoMontellano Нет, он не ведет себя как тип значения, он ведет себя как ссылочный тип, потому что это именно то, что он есть. Вы не создаете копию значения, вы создаете копию ссылки. - person Servy; 16.01.2014

Давайте посмотрим на ваш код построчно

string s = "lana del rey";

С помощью этой строки вы создали строковый объект lana del rey, на который ссылается s

string d = s;

с помощью этой строки вы создали ссылку с именем d, которая ссылается на тот же объект в памяти (в данном случае это lana del rey) с s

s = "elvis presley";

С помощью этой строки вы создали новый строковый объект elvis presley, на который ссылается s (s больше не ссылается на lana del rey)

Console.Writeline(d);

Поскольку d по-прежнему ссылается на lana del rey, печатается lana del rey.

person Soner Gönül    schedule 15.01.2014

Строки обрабатываются иначе, чем обычные ссылочные типы, это, по сути, то, что делает компилятор:

string s = new String("lana del rey");
string d = new String(s);
s = new String("elvis presley");
Console.Writeline(d);

Точка - это «ссылка на строку», указывающая на строку VALUE of s. Каждый раз, когда создается НОВАЯ строка и на нее ссылаются, это новая строка, и любые «ссылки» на исходное значение остаются неизменными.

person T McKeown    schedule 15.01.2014
comment
Моя точка - это строковая ссылка, указывающая на строку VALUE of s. Каждый раз, когда создается НОВАЯ строка и на нее ссылаются, это новая строка, и любые ссылки на исходное значение остаются неизменными. - person T McKeown; 16.01.2014
comment
И все же, на самом деле этого нет в вашем ответе. Наверное, лучше сказать об этом прямо. Я сомневаюсь, что кто-то с уровнем квалификации ОП может сделать такой вывод, увидев этот код. - person Servy; 16.01.2014
comment
Чтобы свести это к минимуму, КАЖДОЕ присвоение строк является НОВОЙ строкой, как еще вы это объясните? - person T McKeown; 16.01.2014
comment
Я просто пытаюсь отметить здесь несколько моментов ... Я отредактирую свой ответ. знак равно - person T McKeown; 16.01.2014
comment
Более или менее так, как вы это сделали в своем первом комментарии. Я просто говорю, что этот комментарий должен был быть в вашем ответе, а не в комментарии. - person Servy; 16.01.2014
comment
Строки обрабатываются иначе, чем обычные ссылочные типы - так ли это на самом деле? Как же так? - person zerkms; 16.01.2014
comment
Да, если вы создадите 2 строковые переменные и присвоите каждой из них значение Hello, они будут указывать на ТО ЖЕ значение. Существует зарезервированная область памяти, предназначенная для хранения строк, и это причина того, что объединение строк настолько дорого, поэтому StringBuilder (). - person T McKeown; 16.01.2014
comment
вот почему логика вроде: if (hello == hello) работает неявно, эти 2 строки являются ОДНИМ значением / хэш-кодом - person T McKeown; 16.01.2014
comment
@zerkms Они отличаются тем, что имеют буквальное значение времени компиляции помимо null. Для этого типа существует прямая поддержка компилятором. Для него также есть псевдоним string. Кроме того, это обычный ссылочный тип. - person Servy; 16.01.2014
comment
@TMcKeown Это работает, потому что == перегружен для сравнения значений строк, а не ссылок. Интернирование - это причина, по которой object.ReferenceEquals("hi","hi") возвращает истину (если итерация включена). - person Servy; 16.01.2014
comment
привет и привет указывают на одну и ту же ссылку. Вы говорите, что это неправда? - person T McKeown; 16.01.2014
comment
Думаю, вы со мной согласны ... yoda.arachsys.com/csharp/strings. html - person T McKeown; 16.01.2014
comment
@TMcKeown Они указывают на ту же ссылку, но "hi" == "hi" возвращает истину не поэтому. Это вернулось бы, даже если бы они не были интернированы. "hi" == new string("hi") также возвращает истину, несмотря на то, что они ссылаются на разные ссылки. - person Servy; 16.01.2014
comment
ах, вы говорите, что, поскольку они интернированы, они одинаковы ... но даже если бы они не были, они были бы такими же, потому что оператор равенства переопределен для поддержки соответствия строкового значения да? Мне нравится с тобой разговаривать ... очень хорошо осведомлен. - person T McKeown; 16.01.2014

Из книги Microsoft .NET Framework 2.0 Application Development Foundation 70 536:

"Поскольку ссылочные типы представляют адрес данных, а не сами данные, присвоение одной ссылочной переменной другой не копирует данные. Вместо этого, присвоение ссылочной переменной другому экземпляру просто создает вторую копию ссылки, которая относится к тот же участок памяти в куче, что и исходная переменная ".

Тогда я думаю:

string s = "lana del rey"; // (creates a reference to the memory location X)
string d = s; // (creates a copy of the reference to the same memory location X)
d = "elvis presley"; // (creates a new reference to the new memory location Y)
person Alberto Montellano    schedule 15.01.2014