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

Постоянное значение, не изменяющееся при перекомпиляции ссылки на сборку

У меня есть этот код в сборке:

public class Class1
{
    public const int x = 10;
}

и в другой сборке:

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine(Class1.x);
        Console.ReadKey();
    }
}

Конечно, результат был 10, но затем я изменил x на 20:

public class Class1
{
    public const int x = 20;
}

Я перекомпилировал сборку и переместил ее в каталог bin в командной строке. Однако выход моей программы был еще 10, пока я не скомпилировал сборку, содержащую функцию main.

Почему это происходит?

4b9b3361

Ответ 1

Значения констант в С# устанавливаются на месте, где они используются. То есть строка Console.WriteLine(Class1.x); будет скомпилирована до Console.WriteLine(10);. Сгенерированный IL-код будет выглядеть так:

  .entrypoint
  .maxstack  8
  IL_0000:  nop
  IL_0001:  ldc.i4.s   10  // here just integer value 10 is loaded on stack
  IL_0003:  call       void [mscorlib]System.Console::WriteLine(int32)

Ссылка на Class1 не будет. Итак, до тех пор, пока вы не перекомпилируете сборку Main, она будет иметь встроенное значение 10. MSDN имеет предупреждение об этом случае использования констант:

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

Они упоминают, что константные выражения оцениваются только во время компиляции. То есть Class1.x будет оцениваться в Main время компиляции сборки для значения 10. И без повторной компиляции это значение не изменится. Но, к сожалению, это не ясно объясняет причину такого поведения (по крайней мере, для меня).

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

Ответ 2

Это метод, называемый константной складкой, используемой при компиляции. Короче говоря, компилятор ищет значения, которые могут быть определены во время компиляции, вычисляет эти значения и записывает их непосредственно в exe файл. Это ускоряет выполнение окончательного машинного кода. Этот метод применяется к другим многим скомпилированным языкам, таким как C, С++.