Страницы

Поиск по вопросам

среда, 27 ноября 2019 г.

В чем проявляется “ссылочность” строк в C#

#c_sharp #.net #строки


Строки в C# - ссылочный тип. Но следующий код

string s1 = "string 1";
string s2 = s1;
s2 = "string 2";
Console.Write(s1);


выведет string 1.
В чем же проявляется "ссылочность" строк в C#?
    


Ответы

Ответ 1



Всё в порядке. string s1 = "string 1"; string s2 = s1; bool b = string.ReferenceEquals(s1, s2); // -> true s2 = "string 2"; bool b2 = string.ReferenceEquals(s1, s2); // -> false Т.е. до того, как вы написали s2 = "string 2", s1 и s2 ссылались на один и тот же объект, но как только вы это написали, был создан новый объект и s2 стала ссылаться на него, а s1 так и осталась ссылаться на первый объект.

Ответ 2



Разница между reference-типами и value-типами существенна только для изменяемых типов. Например, если бы поддерживалась операция s2 += "string 2", то изменения коснулись бы обеих переменных. Однако строка — неизменяемый тип. Содержание строки задаётся один раз при создании, после этого никакие операции не влияют на значение данного экземпляра. Все операции над строкой возвращают либо новый экземпляр, либо тот же самый. Поэтому мы и не можете наблюдать "ссылочность" строк. Впрочем, если пролезть в приватные члены класса строки с помощью отражений, то вы сможете изменить данные. И в этом случае ссылочность будет проявляться, потому что изменение данных, хранящихся по ссылке в одной переменной, приведёт к изменению данных в другой. Но так делать не стоит, конечно. :)

Ответ 3



Переменные ссылочного типа данных ссылаются на объект в куче. По сути, такие переменные это просто ссылки. Подробнее можно почитать на MSDN. Однако со строками несколько сложнее. Вследствие ряда причин, в частности свойства неизменяемости строк и реализации операции сравнения (==), работа с ними почти не отличается от работы с типом значения. Хотя на самом деле это не так. В "обычной практике" о том, что это ссылочный тип говорит разве что тот факт, что строка может принимать значение null.

Ответ 4



"Ссылочность" строк (как и других ссылочных типов) выражается в первую очередь в том, что они передаются (копируются) по ссылке, а не по значению. Это главный признак ссылочных типов. Изменяемость, которая у строк отсутствует, является просто следствием "ссылочности" (тип string в этом отношении особый). А расположение ссылочных типов в куче (что часто называют главным признаком ссылочных типов) -- всего лишь деталь реализации. Однако в вашем рассуждении есть ошибка. Смотрите, что происходит построчно: string s1 = "string 1"; Переменная s1 ссылается на объект "string 1": s1 --> "string 1" string s2 = s1; Переменная s2 ссылается на тот же объект, что и s1: s1 --> "string 1" s2 --------/\ s2 = "string 2"; Переменная s2 ссылается на объект "string 2", при этом ссылка s1 никак не меняется (вы же ведь меняете ссылку у s2, а не s1, так?): s1 --> "string 1" s2 --> "string 2" Рекомендую почитать Джеффри Рихтера "CLR via C#".

Ответ 5



Строка не копируется, а передается ссылка на строку string s1 = "string 1"; string s2 = s1; Т.е. в памяти находится одна строка "string 1" и две ссылки не нее. Даже если одинаковые строки определены в разных методах, в памяти находится только одна строка, т.к. строки являются интернироваными. string s1() { return "111"; } string s2() { return "111"; } string.ReferenceEquals(s1(), s2()) // true s1() == s2() // true Но если строка собирается из частей, то в памяти может быть две одинаковые строки. string s1() { return new string('1', 3); } string s2() { return new string('1', 3); } string.ReferenceEquals(s1(), s2()) // FALSE s1() == s2() // true Чтобы убрать дубли, строки надо интернировать string s1() { return string.Intern(new string('1', 3)); } string s2() { return string.Intern(new string('1', 3)); } string.ReferenceEquals(s1(), s2()) // true s1() == s2() // true

Ответ 6



Вставлю свои пять копеек. "Ссылочность" может проявляться например в отсутствии упаковки. Пример: int i = 10; object o = i; // тут упаковка происходит, т.к. int - value type string str = "asdasd"; object o2 = str; // здесь упаковка не происходит, поскольку string - reference type Проверить это можете в утилите ildasm - для первого случая будет сгенерирована команда box, для второго - нет. Также "ссылочность" проявляется в передаче по ссылке, а не по значению - строки слишком велики, для того, чтобы каждый раз их копировать при передаче в метод в качестве параметра. Размер string в .NET может быть до 2 Гб - было бы не слишком круто, если бы это требовалось передавать по значению.

Комментариев нет:

Отправить комментарий