Почему 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

Надеюсь, это должно помочь вам лучше понять, почему