Почему String является типом Value, хотя это класс, а не структура? - PullRequest
11 голосов
/ 02 сентября 2011

Возьмем следующий пример:

string me = "Ibraheem";
string copy = me;
me = "Empty";
Console.WriteLine(me);
Console.WriteLine(copy);

Вывод:

Empty
Ibraheem

Поскольку это тип класса (т.е. не структура), строка copy также должна содержать Empty потому что = operator в C # назначает ссылку на объекты, а не на сам объект (как в C ++) ??

Ответы [ 8 ]

18 голосов
/ 02 сентября 2011

Хотя принятый ответ касается этого (как и некоторых других), я хотел дать ответ, посвященный тому, что, по-видимому, вы на самом деле спрашиваете, а именно о семантике присваивания переменных.

Переменные в C # - это просто фрагменты памяти, отведенные для хранения одного значения. Важно отметить, что не существует такой вещи, как «переменная значения» и «ссылочная переменная», поскольку переменные содержат только значения.

Различие между «значением» и «ссылкой» связано с типом. Тип значения (VT) означает, что весь фрагмент данных хранится в переменной.

Если у меня есть целочисленная переменная с именем abc, которая содержит значение 100, то это означает, что в моем приложении есть четырехбайтовый блок памяти, в котором хранится буквенное значение 100. Это связано с тем, что int является типом значения и, следовательно, все данные хранятся в переменной.

С другой стороны, если у меня есть переменная string с именем foo, которая содержит значение "Adam", то здесь задействованы две фактические ячейки памяти. Первый - это часть памяти, в которой хранятся действительные символы "Adam", а также другая информация о моей строке (ее длина и т. Д.). ссылка на это местоположение сохраняется в моей переменной. Ссылки очень похожи на указатели в C / C ++; хотя они не совпадают, для этого объяснения достаточно аналогии.

Итак, чтобы подвести итог, значением для ссылочного типа является ссылка на другое место в памяти, где значением для типа значения является сами данные .

Когда вы присваиваете что-то переменной, все, что вы изменяете, это значение переменной . Если у меня есть это:

string str1 = "foo";
string str2 = str1;

Тогда у меня есть две строковые переменные, которые содержат одно и то же значение (в этом случае каждая из них содержит ссылку на одну и ту же строку, "foo".) Если затем сделать это:

str1 = "bar";

Затем я изменил значение str1 на ссылку на строку "bar". Это совсем не меняет str2, так как его значение все еще является ссылкой на строку "foo".

9 голосов
/ 02 сентября 2011

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?Если это так, у вас есть неправильное понимание языка.

В вашем примере вы присвоили строке значение.Вот и все.Он не имеет ничего общего с типами значений, ссылочными типами, классами или структурами.Это простое задание, и это правда, говорите ли вы о строках, long или Foos.Ваши переменные временно содержали то же значение (ссылка на строку «Ibraheem»), но затем вы переназначали одну из них.Эти переменные не были неразрывно связаны между собой, они просто временно содержали нечто общее.

8 голосов
/ 02 сентября 2011

Это не тип значения.Когда вы используете строковый литерал, это на самом деле ссылка, сохраненная при компиляции.Поэтому, когда вы присваиваете строку, вы в основном меняете указатель, как в C ++.

6 голосов
/ 02 сентября 2011

Строки ведут себя так же, как и любой другой класс.Обратите внимание:

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.

3 голосов
/ 02 сентября 2011

В вашем примере показано классическое поведение ссылочного типа в виде строки.

2 голосов
/ 02 сентября 2011

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

int me = 1;
int copy = me;
me = 2;
Console.WriteLine(me);
Console.WriteLine(copy);

Это напечатает следующее:

2
1
2 голосов
/ 02 сентября 2011

string copy = me; означает, что ссылка copy будет указывать на ту же область памяти, куда указывает me.

Позже me может указывать на другую область памяти, но это не повлияет на copy.

0 голосов
/ 02 сентября 2011

В то время как в других ответах говорилось, каково именно решение вашего ответа, чтобы лучше понять, почему вы захотите прочитать информацию о распределении памяти в куче и стеке и когда данные удаляются из памяти сборщиком мусора .

Вот хорошая страница, которая описывает стек, кучу памяти и сборщик мусора. В нижней части статьи есть ссылки на другие части объяснения: http://www.c -sharpcorner.com / UploadFile / rmcochran / csharp_memory01122006130034PM / csharp_memory.aspx? ArticleID = 9adb0e3c-b3f6-40b5-98b5-413b6d348b91

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

...