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

imageВітаю. Нещодавно я натрапив на статтю товариша Dywar «Цікаві замітки з C# і CLR» і зацікавився пунктом 13:

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

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

public class Master
{
public const Const string = "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 могло породити «баг незмінною константи».

Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.