Странное сравнение строкового литерала - PullRequest
16 голосов
/ 30 ноября 2011

Углубившись в C #, я столкнулся с небольшой (странной) проблемой с равенством ссылок на объекты. Пусть говорит, что у меня есть две строки:

String a = "Hello world!";
String b = "Bonjour le monde";
bool equals = ReferenceEquals(a, b);  // ******************* (1)
b = "Hello world!";
equals = ReferenceEquals(a, b);       // ******************* (2)

(1) равно false, и это ожидается. ReferenceEquals Документация говорит

ReferenceEquals сравнивает экземпляры

но потом:

  • Почему (2) возвращает true?
  • Строки a и b не являются одним и тем же объектом, не так ли? Если да, то как они стали одинаковыми, если бы я никогда явно не делал a=b

Ответы [ 4 ]

24 голосов
/ 30 ноября 2011

Это происходит из-за интернирования строк .

Общеязыковая среда выполнения сохраняет хранилище строк, поддерживая таблицу, называемую внутренним пулом, которая содержит одну ссылку на каждый уникальныйСтрока литерала объявлена ​​или создана программно в вашей программе.Следовательно, экземпляр литеральной строки с определенным значением существует только один раз в системе.

Например, если вы назначаете одну и ту же строку литерала нескольким переменным, среда выполнения получает одну и ту же ссылку на строку литерала извнутренний пул и назначает его каждой переменной.

9 голосов
/ 30 ноября 2011

Строковые литералы автоматически интернируются средой выполнения .NET. Это означает, что один и тот же экземпляр строки является общим для строковых литералов с одинаковым значением. Это сделано, чтобы уменьшить использование памяти и улучшить производительность. Это безопасная оптимизация, потому что строки неизменны.

Ваш код компилируется в CIL инструкции, подобные следующим:

IL_0001: ldstr "Hello world!"
IL_0006: stloc.0
IL_0007: ldstr "Bonjour le monde"
IL_000c: stloc.1
etc...

Из документации инструкции ldstr ("загрузить буквенную строку") в спецификации ECMA :

По умолчанию CLI гарантирует, что результат двух инструкций ldstr, относящихся к двум токенам метаданных, которые имеют одинаковую последовательность символов, возвращают точно такой же строковый объект (процесс, известный как "строка" interning "). Это поведение можно контролировать с помощью System.Runtime.CompilerServices.CompilationRelaxationsAttribute и System.Runtime.CompilerServices.CompilationRelaxations.NoStringInterning.

Вы также можете сами интернировать строки, вызывая метод String.Intern .

4 голосов
/ 30 ноября 2011

Строковые литералы большую часть времени являются одним и тем же объектом, поскольку они являются постоянными и неизменными.

Взяты из microsoft docs :

Каждый строковый литералне обязательно приводит к новому экземпляру строки.Когда два или более строковых литерала, эквивалентных по оператору равенства строк (раздел 7.9.7), появляются в одной сборке, эти строковые литералы ссылаются на один и тот же экземпляр строки.Например, вывод, полученный с помощью

class Test
{
   static void Main() {
      object a = "hello";
      object b = "hello";
      System.Console.WriteLine(a == b);
   }
}

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

3 голосов
/ 30 ноября 2011

.NET поддерживает пул строк, так как они неизменны.Вам не нужно заботиться об этом, поскольку он сам позаботится об их повторном использовании.

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