Стринг интернирующий?

Второй вызов ReferenceEquals возвращает false. Почему строка в s4 не интернирована? (Меня не волнует преимущество StringBuilder перед конкатенацией строк.)

string s1 = "tom";
string s2 = "tom";


Console.Write(object.ReferenceEquals(s2, s1)); //true

string s3 = "tom";
string s4 = "to";
s4 += "m";

Console.Write(object.ReferenceEquals(s3, s4)); //false

Когда я делаю String.Intern(s4);, я все равно получаю ложь.

Здесь и s3, и s4 интернированы, но их ссылки не равны?

string s3 = "tom";
string s4 = "to";
s4 += "m";
String.Intern(s4);

Console.WriteLine(s3 == s4); //true
Console.WriteLine(object.ReferenceEquals(s3, s4)); //false
Console.WriteLine(string.IsInterned(s3) != null);  //true (s3 is interned)
Console.WriteLine(string.IsInterned(s4) != null);  //true (s4 is interned)
8
задан Olivier Rogier 7 October 2019 в 17:01
поделиться

4 ответа

Строка в s4 интернирован. Однако, когда вы выполняете s4 + = "m"; , вы создали новую строку, которая не будет интернирована, поскольку ее значение не является строковым литералом, а является результатом операции конкатенации строк. В результате s3 и s4 представляют собой два разных экземпляра строки в двух разных ячейках памяти.

Дополнительную информацию об интернировании строк можно найти в здесь , особенно в последнем примере. Когда вы выполняете String.Intern (s4) , вы действительно интернируете строку, но все еще не выполняете проверку на равенство ссылок между этими двумя интернированными строками. Метод String.Intern возвращает интернированную строку, поэтому вам нужно будет сделать следующее:

string s1 = "tom";
string s2 = "tom";

Console.Write(object.ReferenceEquals(s2, s1)); //true 

string s3 = "tom";
string s4 = "to";
s4 += "m";

Console.Write(object.ReferenceEquals(s3, s4)); //false

string s5 = String.Intern(s4);

Console.Write(object.ReferenceEquals(s3, s5)); //true
17
ответ дан 5 December 2019 в 06:22
поделиться

Во-первых, все, что до сих пор написано о неизменяемых строках, правильно. Но есть некоторые важные вещи, о которых не написано. В коде

string s1 = "tom";
string s2 = "tom";
Console.Write(object.ReferenceEquals(s2, s1)); //true

действительно отображается «True», но только из-за небольшой оптимизации компилятора или как здесь, потому что CLR игнорирует атрибуты компилятора C # (см. Книгу «CLR через C #») и помещает только одну строку «tom» в куче.

Во-вторых, вы можете исправить ситуацию с помощью следующих строк:

s3 = String.Intern(s3);
s4 = String.Intern(s4);
Console.Write (object.ReferenceEquals (s3, s4)); //true

Функция String.Intern вычисляет хеш-код строки и ищет такой же хеш во внутренней хеш-таблице. Поскольку он находит это, он возвращает ссылку на уже существующий объект String . Если строка не существует во внутренней хеш-таблице, создается копия строки и вычисляется хэш. Сборщик мусора не освобождает память для строки, потому что на нее ссылается хеш-таблица.

2
ответ дан 5 December 2019 в 06:22
поделиться

В C # каждая строка представляет собой отдельный объект и не может быть изменена. Вы создаете ссылки на них, но каждая строка отличается. Поведение последовательное и понятное.

Могу я предложить изучить класс StringBuilder для управления строками без создания новых экземпляров? Этого должно хватить на все, что вы хотите делать со строками.

1
ответ дан 5 December 2019 в 06:22
поделиться

Строки неизменяемы. Это означает, что их содержимое нельзя изменить.

Когда вы выполняете s4 + = "m"; внутри, CLR копирует строку в другое место в памяти, которое содержит исходную строку и добавленную часть.

См. Ссылка на строку MSDN .

3
ответ дан 5 December 2019 в 06:22
поделиться
Другие вопросы по тегам:

Похожие вопросы: