Почему String - это тип значения, хотя это класс, а не структура?
Возьмем следующий пример:
string me = "Ibraheem";
string copy = me;
me = "Empty";
Console.WriteLine(me);
Console.WriteLine(copy);
Вывод:
Empty
Ibraheem
Поскольку это тип класса (т.е. не struct), String copy
также должен содержать Empty
, потому что = operator
в С# назначает ссылку объектов, а не самого объекта (как на С++)
Ответы
Ответ 1
System.String
не является типом значения. Он демонстрирует некоторые типы поведения, похожие на типы значений, но поведение, с которым вы столкнулись, не является одним из них. Рассмотрим следующий код.
class Foo
{
public string SomeProperty { get; private set; }
public Foo(string bar) { SomeProperty = bar }
}
Foo someOtherFoo = new Foo("B");
Foo foo = someOtherFoo;
someOtherFoo = new Foo("C");
Если вы проверили вывод foo.SomeProperty
, вы ожидаете, что он будет таким же, как someOtherFoo.SomeProperty
? Если это так, у вас есть некорректное понимание языка.
В вашем примере вы присвоили строке значение. Это. Он не имеет ничего общего с типами значений, ссылочными типами, классами или структурами. Это простое назначение, и это правда, говорите ли вы о струнах, длинных или фонов. Ваши переменные временно содержат одно и то же значение (ссылка на строку "Ибрахим" ), но затем вы переназначили один из них. Эти переменные не были неразрывно связаны на все время, они просто что-то временно сохраняли.
Ответ 2
В то время как принятый ответ адресован этому (как и некоторые другие), я хотел дать ответ, посвященный тому, что кажется, что вы действительно спрашиваете, что касается семантики присваивания переменной.
Переменные в С# - это просто части памяти, которые зарезервированы для хранения одного значения. Важно отметить, что нет такой вещи, как "переменная значения" и "ссылочная переменная", поскольку переменные содержат только значения.
Различие между "значением" и "ссылкой" относится к типу. Тип значения (VT) означает, что весь фрагмент данных хранится внутри переменной.
Если у меня есть целочисленная переменная с именем abc
, которая содержит значение 100
, то это означает, что у меня есть четырехбайтовый блок памяти в моем приложении, в котором хранится буквальное значение 100
внутри него. Это связано с тем, что int
- это тип значения, и, следовательно, все данные сохраняются внутри переменной.
С другой стороны, если у меня есть переменная string
с именем foo
, которая содержит значение "Adam"
, тогда есть два фактических места памяти. Первый - это кусок памяти, в котором хранятся фактические символы "Adam"
, а также другая информация о моей строке (ее длина и т.д.). Ссылка на это местоположение затем сохраняется в моей переменной. Ссылки очень похожи на указатели на C/С++; в то время как они не совпадают, аналогии достаточно для этого объяснения.
Итак, чтобы подвести итог, значение для ссылочного типа является ссылкой на другое место в памяти, где значением для типа значения являются сами данные.
Когда вы присваиваете что-то переменной, все, что вы меняете, это значение переменной. Если у меня есть это:
string str1 = "foo";
string str2 = str1;
Затем у меня есть две строковые переменные, которые содержат одно и то же значение (в этом случае каждый из них содержит ссылку на ту же строку, "foo"
.) Если тогда сделайте это:
str1 = "bar";
Затем я изменил значение str1
на ссылку на строку "bar"
. Это вообще не изменяет str2
, так как его значение по-прежнему является ссылкой на строку "foo"
.
Ответ 3
Это не тип значения. Когда вы используете строковый литерал, его фактическая ссылка сохраняется при компиляции. Поэтому, когда вы назначаете строку, вы в основном меняете указатель, как на С++.
Ответ 4
Строки ведут себя так же, как и любой другой класс. Рассмотрим:
class Test {
public int SomeValue { get; set; }
public Test(int someValue) { this.SomeValue = someValue; }
}
Test x = new Test(42);
Test y = x;
x = new Test(23);
Console.WriteLine(x.SomeValue + " " + y.SomeValue);
Вывод:
23 42
- точно такое же поведение, как в вашем примере string
.
Ответ 5
То, что показывает ваш пример, - это классическое поведение ссылочного типа, в котором находится строка.
Ответ 6
string copy = me;
означает, что ссылка copy
будет указывать на ту же ячейку памяти, где указывается me
.
Позже me
может указывать на другую ячейку памяти, но это не повлияет на copy
.
Ответ 7
Ваш код будет делать то же самое, если вы также использовали типы значений. Рассмотрим использование целых чисел:
int me = 1;
int copy = me;
me = 2;
Console.WriteLine(me);
Console.WriteLine(copy);
При этом будет напечатано следующее:
2
1
Ответ 8
В то время как другие ответы говорят точно, каково решение вашего ответа, чтобы получить более полное фундаментальное понимание того, почему вы хотите получить информацию о распределении памяти кучи и стека и когда данные удаляются из памяти сборщиком мусора.
Вот хорошая страница, описывающая стек и память кучи и сборщик мусора. В нижней части статьи есть ссылки на другие части объяснения:
http://www.c-sharpcorner.com/UploadFile/rmcochran/csharp_memory01122006130034PM/csharp_memory.aspx?ArticleID=9adb0e3c-b3f6-40b5-98b5-413b6d348b91
Надеюсь, это должно помочь вам лучше понять, почему