Pull to refresh

Константы не меняются: небольшой экскурс в глубины dotNet

Reading time2 min
Views11K
image Приветствую. Недавно я наткнулся на статью товарища Dywar «Интересные заметки по C# и CLR» и заинтересовался пунктом 13:

«Константы помещаются в метаданные сборки, поэтому если были изменения, нужно перекомпилировать все использующие ее сборки. Т.к. DLL с константой может даже не загружаться.»

Да ладно, подумал я, и полез ставить эксперименты. Создал проект TestConstants, в нем класс,

public class Master
    {
        public const string Const = "Hello world";
    }

затем проект TestConstantsSlave,

static void Main()
        {
            Console.WriteLine(Master.Const);
            Console.ReadKey();
        }

Заменил константу на “Hello habr”, перебилдил основной проект, запустил по F5…

На консоли высветился “Hello habr”. Видимо, студия ребилднула заодно и Slave проект. В принципе, на этом можно было успокоиться, но хотелось немного поэкспериментировать.

Первым делом я заменил константу на “Greetings, sir von Neumann”, ребилднул основной проект, и запустил Slave через проводник → TestConstantsSlave.exe. На консоли светилось «Hello habr», да простит меня великий Нейман. Скопировал свежую библиотеку к Slave – по прежнему «Hello habr”. Удалил TestConstants библиотеку — снова “Hello habr”. Хабр молчал.

Неужели действительно константа копируется в метаданные? Открываем ildasm. В манифесте Slave все стандартно: версия, заголовки, токены. Константы нет (что разумно). Пробежал по классам — никаких метаданных в явном виде не обнаружено.

Зато в коде Slave есть «Hello habr» в явном виде.

ildasm

Смотрим описание инструкции ldstr на msdn. “Pushes a new object reference to a string literal stored in the metadata“. Видимо, метаданные скрыты для ildasm. На всякий случай проверил dotPeek – результат аналогичен (зато видно, что Slave проект не ссылается на TestConstants).

Проверка константы другого типа: использование Int32 константы дает другой il код: ldc.i4.5. Здесь у нас простой пуш инта в стек (что опять-таки разумно — строки длинные, есть смысл их кэшировать, а вот накладные расходы на вытягивание инта из кэша перевешивают выхлоп). Видимо, в изначальной статье и msdn под метаданными подразумевается часть механизма интернирования строк (тунц, тынц), что, кстати, объясняет отсутствие метаданных в ildasm — пул строк генерируется для процесса.

И что дальше?


Ничего страшного. Студия же правильно билдит, да и константы меняются не каждый день. С другой стороны, я уже работал с проектом, где SDK и использующие его утилиты находились в разных солюшнах, и обновление SDK могло породить «баг неизменной константы».
Only registered users can participate in poll. Log in, please.
Встречались ли вы с «багом неизменной константы»?
13.48% Да36
86.52% Нет231
267 users voted. 97 users abstained.
Only registered users can participate in poll. Log in, please.
Стоит ли расследовать детали работы nameof()?
79.58% Да191
20.42% Нет49
240 users voted. 111 users abstained.
Tags:
Hubs:
Total votes 29: ↑19 and ↓10+9
Comments18

Articles