ReferenceEquals работает неправильно со строками

Почему в этой ситуации ReferenceEquals метод объекта ведет себя иначе?

string a= "fg";
string b= "fg";
Console.WriteLine(object.ReferenceEquals(a, b));

Так что в этой ситуации получается результат true, В случае, он сравнивает значения моих строк, а не ссылки. Но когда я пишу что-то вроде:

StringBuilder c = new StringBuilder("fg");
string d = c.ToString();
Console.WriteLine(object.ReferenceEquals(a, d));

В этом случае он работает нормально, и результат false, потому что он сравнивает ссылки на мои объекты.

5 ответов

Решение

Первый пример имеет постоянную времени компиляции "fg" на что ссылаются две переменные. Поскольку это постоянная времени компиляции, две переменные ссылаются на один объект. Ссылки равны.

Читайте в теме интернирования строк для получения дополнительной информации об этом поведении. Для начала рассмотрим:

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

http://msdn.microsoft.com/en-us/library/system.string.intern.aspx

Во втором примере только одна является постоянной времени компиляции, другая является результатом некоторых операций. a а также d не ссылаться на один и тот же объект, поэтому вы получите ложный результат от ReferenceEquals,

Это ведет себя правильно в обоих случаях.

Причина a а также b один и тот же строковый объект, потому что компилятор заметил, что вы указали одну и ту же строку дважды, и повторно использовал один и тот же строковый объект для инициализации обоих a а также b,

Это обычно происходит с каждой строковой константой в вашем приложении.

Это связано с тем, что CLR с версией выше 4.5 сборки помечены атрибутом System.Runtime.CompilerServices.CompilationRelaxations Attributeкоторый определяет значение флага System.Runtime.CompilerServices. CompilationRelaxations.NoStringInterning.Это было реализовано с целью повышения производительности.

Если запустить ваш код в версии CLR ниже 4.5, переменные и будут ссылаться на разные строковые объекты в куче со значением «fg» и дадут результат «False».

Начиная с CLR 4.5 сравнение object.ReferenceEquals(a, b)даст результат «True», потому что он интернирует строку «fg» при загрузке сборки в домен приложения. Это означает, что aа также bссылки на одну и ту же строку в куче.

Поскольку вы ссылаетесь на один и тот же литерал ("fg"), обе ваши строки будут фактически указывать на одну и ту же вещь. Пожалуйста, ознакомьтесь с этой статьей: http://csharpindepth.com/Articles/General/Strings.aspx (пункт "Стажировка").

С уважением, Петр

Согласно этому посту, это связано с тем, что называется интернированием. a и b в вашем случае две переменные, указывающие на один и тот же экземпляр, поэтому ReferenceEquals возвращает true.

Другие вопросы по тегам