С# действительно ли строковые литералы оптимизируются компилятором?
Является ли компилятор С# или .NET CLR какой-либо умной оптимизацией памяти строковых литералов/констант? Я мог бы поклясться, что слышал о понятии "интернализации строк", так что в любых двух битах кода в программе литерал "это строка" фактически ссылался бы на один и тот же объект (предположительно безопасный, что со строками, являющимися неизменный?). Я не могу найти полезную ссылку на него в Google, хотя...
Я слышал это неправильно? Не волнуйтесь - я не делаю ничего ужасного в своем коде с этой информацией, просто хочу лучше понять, как это работает под обложками.
Ответы
Ответ 1
EDIT: Хотя я сильно подозреваю, что приведенное ниже утверждение верно для всех реализаций компилятора С#, я не уверен, что это действительно гарантировано в спецификации. В разделе 2.4.4.5 спецификации говорится о литералах, относящихся к одному и тому же строковому экземпляру, но в нем не упоминаются другие константные строковые выражения. Я подозреваю, что это оплошность в спецификации - я напишу об этом Mads и Eric.
Это не просто строковые литералы. Это любая строковая константа. Например, рассмотрим:
public const string X = "X";
public const string Y = "Y";
public const string XY = "XY";
void Foo()
{
string z = X + Y;
}
Компилятор понимает, что конкатенация здесь (для z
) находится между двумя константными строками, поэтому результат также является константой. Поэтому начальное значение z
будет той же ссылкой, что и значение XY
, поскольку они являются константами времени компиляции с одинаковым значением.
EDIT: ответ Мэдса и Эрика предположил, что в корневом компиляторе Microsoft С# строковые константы и строковые литералы обычно обрабатываются одинаково - но другие реализации могут отличаться.
Ответ 2
Да, он оптимизирует строковые литералы. Один простой пример, где вы можете видеть, что:
string s1="A";
string s2="A";
object.ReferenceEquals(s1,s2); //true
Ответ 3
В этой статье объясняется, что интернирование строк довольно хорошо. Цитата:
.NET имеет концепцию "intern" пул ". Это в основном просто набор но он гарантирует, что каждый время, когда вы ссылаетесь на одну и ту же строку буквально, вы получаете ссылку на ту же строку. Это, вероятно, зависит от языка, но это, безусловно, true в С# и VB.NET, и я был бы очень удивлен, увидев язык, на котором он не удерживайте, поскольку IL делает очень легким (возможно, легче, чем не литераторы интернирования). Как и литералы будучи автоматически интернированным, вы можете внутренняя строка вручную с помощью Intern метод, и проверьте, нет уже интернированных строка с тем же символом последовательности в пуле с использованием Метод IsInterned. Это несколько неинтуитивно возвращает строку чем логическое - если равная строка в пуле, ссылка на это строка возвращается. В противном случае, null вернулся. Аналогично, метод Интернационала возвращает ссылку на интернированного string - строка, которую вы передали в, если был уже в пуле, или вновь созданная интернированная строка или равная строка, которая уже была в бассейн.
Ответ 4
http://en.csharp-online.net/CSharp_String_Theory%E2%80%94String_intern_pool
http://msdn.microsoft.com/en-us/library/system.string.isinterned.aspx
http://msdn.microsoft.com/en-us/library/system.string.intern.aspx