Это из-за пула строк с помощью CLR или метода GetHashCode ()? - PullRequest
1 голос
/ 31 марта 2009

Это из-за того, что CLR или метод GetHashCode () обеих строк возвращают одинаковое значение?

string s1 = "xyz";
string s2 = "xyz";
Console.WriteLine(" s1 reference equals s2 : {0}", object.ReferenceEquals(s1, s2));

Консоль пишет: "ссылка s1 равна s2: True"

Я считаю, что это не потому, что GetHashCode () возвращает одинаковое значение для обоих экземпляров строки. Потому что я протестировал пользовательский объект и переопределил метод GetHasCode (), чтобы каждый раз возвращать одну константу. Два отдельных экземпляра этого объекта не равны в ссылке.

Пожалуйста, дайте мне знать, что происходит за сценой.

спасибо 123Developer

Ответы [ 5 ]

14 голосов
/ 31 марта 2009

Звучит как интернирование строк - метод хранения только одной копии строки. Требуется, чтобы строки были неизменным типом в языке, с которым вы имеете дело, и .Net удовлетворяет этому и использует интернирование строк.

В интернировании строк строка «xyz» хранится в пуле интернирования, и всякий раз, когда вы говорите «xyz» внутри, она ссылается на запись в пуле. Это может сэкономить место, сохраняя строку только один раз. Таким образом, сравнение «xyz» == «xyz» будет интерпретировано как [указатель на 34576] == [указатель на 34576], что верно.

6 голосов
/ 31 марта 2009

Это определенно связано с интернированием строк. Хеш-коды никогда не рассчитываются при сравнении ссылок с object.ReferenceEquals.

Из спецификации C #, раздел 2.4.4.5:

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

Обратите внимание, что строковые константные выражения в этом случае считаются литералами, поэтому:

string x = "a" + "b";
string y = "ab";

Гарантируется, что x и y также относятся к одному и тому же объекту (т. Е. Они являются одинаковыми ссылками).

Когда спецификация, кстати, говорит «программа», это действительно означает «сборка». Поведение одинаковых строк в разных сборках зависит от таких вещей, как CompilationRelaxations.NoStringInterning и точной ситуации реализации и времени CLR (например, является ли сборка ngen'd или нет).

4 голосов
/ 31 марта 2009

Это похоже на пул строк, но не во время выполнения, а во время компиляции.

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

Если вместо этого вы создаете строку во время выполнения, вы получаете отдельный экземпляр:

string s1 = "xyz";

string s2 = "xy";
s2 += "z";

Console.WriteLine("s1 ref = s2 : {0}", object.ReferenceEquals(s1, s2));

Выход:

s1 ref = s2 : False
0 голосов
/ 31 марта 2009

интернирование строк не имеет к этому никакого отношения.

Я был бы очень удивлен, обнаружив, что компилятор .NET / C # вызывает Intern неявно. Процессору требуется слишком много нагрузки для проверки соответствия строки во время выполнения.

0 голосов
/ 31 марта 2009

Полностью согласен с Ответом Тома ...

Выдержка из CIL Спецификация (стр. 126) :

CLI гарантирует, что результат две инструкции ldstr, относящиеся к два токена метаданных с одинаковыми последовательность символов, возврат точно такой же строковый объект ( процесс, известный как «интернирование строк»).

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