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

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

7 голосов
/ 25 апреля 2010

Второй вызов 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)

Ответы [ 5 ]

16 голосов
/ 25 апреля 2010

Строка в 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
3 голосов
/ 25 апреля 2010

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

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

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

2 голосов
/ 25 апреля 2010

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

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

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

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

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

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

1 голос
/ 24 сентября 2017

Источник: https://blogs.msdn.microsoft.com/ericlippert/2009/09/28/string-interning-and-string-empty/

Строковое интернирование - это метод оптимизации компилятором. Если у вас есть два одинаковых строковых литерала в одном модуле компиляции, то сгенерированный код гарантирует, что для всего экземпляра этого литерала (символы, заключенные в двойные кавычки) внутри сборки создан только один строковый объект.

Я из C # фона, поэтому я могу объяснить, приведя пример из этого:

object obj = "Int32";
string str1 = "Int32";
string str2 = typeof(int).Name;

вывод следующих сравнений:

Console.WriteLine(obj == str1); // true
Console.WriteLine(str1 == str2); // true    
Console.WriteLine(obj == str2); // false !?

Примечание1 : объекты сравниваются по ссылке.

Примечание2 : typeof (int). Имя оценивается методом отражения, поэтому оно не оценивается во время компиляции. Вот эти сравнения сделаны во время компиляции.

Анализ результатов: 1) истина, потому что они оба содержат одинаковые литералы и поэтому сгенерированный код будет иметь только один объект, ссылающийся на «Int32». См. Примечание 1 .

2) true, потому что проверяется содержимое обоих значений.

3) FALSE, потому что str2 и obj не имеют одинаковые литералы. См. Примечание 2 .

1 голос
/ 25 апреля 2010

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...