2013-02-21 3 views
4

У меня есть пример кода.В чем разница между присваиванием и созданием экземпляра строки в C#?

var charMass = new char[] { 's', 't', 'r' }; 
string myString = new string(charMass); 
string myString2 = new string(charMass); 
string myString3 = "str"; 
string myString4 = "str"; 

bool bb1 = Object.ReferenceEquals(myString, myString2); 
bool bb2 = Object.ReferenceEquals(myString, myString3); 
bool bb3 = Object.ReferenceEquals(myString3, myString4); 

Почему bb1 и bb2 являются фальшивыми? Я знаю, что equals должен показывать true, потому что он сравнивает значения, но как насчет распределения памяти для этих строк? Почему myString3 и myString4 указывают на тот же блок памяти в куче, но myString и myString2 нет?

+0

http://stackoverflow.com/questions/4232789/why-does-referenceequalss1-s2-returns-true Вероятно, выше ссылка поможет вам. –

+0

Эта статья [http://en.wikipedia.org/wiki/String_interning] может объяснить вашу проблему. –

ответ

5

C# компилятор оптимизирует его так, одни и те же литералов указывают на ту же строку, например

MSDN:

Интерн пула хранения сохраняет строку. Если вы назначаете константу строки буквально для нескольких переменных, каждая переменная установлена ​​в , ссылаясь на ту же константу в основном пуле вместо , ссылаясь на несколько разных экземпляров String, которые имеют одинаковые значения .

+0

Я думал, что myString и myString2 тоже должны быть интернированы и ссылаться на один и тот же объект-стажер. Спасибо за ссылку. –

+0

Внутренний пул - это своего рода Hashtable, ключ - строковое значение, значение - ссылка на строку в куче, правильно? –

0

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

+1

Компилятор не оптимизирует * переменные *. Он оптимизирует * литералы *; два идентичных литерала генерируются так, чтобы они указывали на одно и то же место в таблице строк метаданных. –

+0

Спасибо за исправление Эрик. –

1

myString и myString2 никогда не могут ссылаться друг на друга (или на любую другую строку), потому что вы явно вызываете конструктор строк, в результате чего каждый раз создается новый объект. Очевидно, что этот новый объект не будет равным ссылке на любой другой уже существующий объект.

myString3 и myString4 являются референтным равно, так как компилятор interns the strings: строковые значения инициализируются с строковыми литералами во время компиляции, в конечном итоге ссылок на тот же объект во время выполнения:

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

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

0

Это основано на базовой реализации String в структуре.

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

Как я вижу в том, что для MyString и myString2, вы создали те, которые используют символ [] и там не по умолчанию поиск в Intern пуле, как строка создается.

В случае myString3 и myString4, myString3 добавил значение InternPool и для myString4 вы получили ссылку, поскольку это был блок-образец.

Раньше у меня создалось впечатление, что в более ранней версии рамки IsIntern был необязательным и позволял разработчику. Похоже, что это не обязательно так

4

Я отвечу на ваш вопрос здесь:

http://blogs.msdn.com/b/ericlippert/archive/2009/09/28/string-interning-and-string-empty.aspx.

Короткий ответ: интернирование литеральных строк дешево и легко и поэтому сделано по умолчанию. Интерполяция динамически распределенных строк обычно сохраняет небольшое количество байтов за счет огромного количества времени и, следовательно, не стоит беспокоиться о. Если вы хотите сделать интернирование, вы можете сделать это самостоятельно.

+0

Что касается внутренней хэш-таблицы для интернированных строк, которая содержит строковое значение в качестве ключа и ссылки на строку в куче? Рихтер рассказал об этом в своей книге, это какое-то неприкосновенное хранилище в куче, которое живет до тех пор, пока домен приложения не будет выгружен? Мне все еще не ясно. –

+0

@IgorLozovsky: Я не понимаю вопроса, который вы задаете здесь. Вы спрашиваете, как String.Intern реализуется? –

+0

CLR поддерживает хэш-таблицу строк для каждого процесса. Они распределяются между всеми доменами приложения в этом процессе. Эта информация я узнал в книге Джеффри Рихтера. –

Смежные вопросы