Подтвердить что ты не робот

Строковые константы, встроенные дважды в .Net?

Скажем, у меня простая (самая простая?) программа на С#:

class Program {
    static void Main() {
      System.Console.WriteLine("Hello, world");
    }
}

Если я скомпилирую этот код и посмотрю на полученный .exe, я вижу строку "Hello, world" в EXE-изображении, как ожидалось.

Если я реорганизую код на:

class Program {
    const string Greeting = "Hello, world";
    static void Main() {
      System.Console.WriteLine(Greeting);
    }
}

Если я скомпилирую этот код и посмотрю на полученный .exe, я дважды вижу строковый литерал "Hello, world" в EXE-изображении. Это было удивительно для меня. У меня создалось впечатление, что строковые литералы были разделены, и что это могло бы появиться только в изображении один раз. Может кто-нибудь объяснить это? Возможно, эта вторая копия строки необходима для метаданных отражения?

4b9b3361

Ответ 1

спецификация CLI ECMA-335 проливает свет на это. С# const объявляется как поле static literal в IL. Из раздела I.8.6.1.2 (основное внимание):

Литеральное ограничение promises, что значение местоположения на самом деле является фиксированным значением встроенного типа. Значение указано как часть ограничения. Составители требуется заменить все ссылки на местоположение с его значением, и, следовательно, VES не нужно выделять место для местоположения. Это ограничение, логически применимое к любое место, должно быть помещено только в статические поля сложных типов. Поля, которые так что на них не разрешено ссылаться на CIL (они должны быть привязаны к их постоянное значение во время компиляции), но доступны с использованием отражений и инструментов, которые непосредственно обрабатывать метаданные.

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