В .NET почему константы оцениваются во время компиляции, а не во время JIT?
Сегодня я немного удивился, когда изменил значение публично видимой константы в статическом классе, а затем заменил старую копию сборки на недавно скомпилированную версию. Удивительно, что существующая программа, которая ссылалась на сборку, не получила нового значения константы. То есть я не перекомпилировал исполняемый файл, а просто заменил эту сборку.
Полное описание моего эксперимента находится в Как константа является константой?
Я признаю, что очень удивлен этим поведением. Я понимаю, что происходит, но я не понимаю, почему. Есть ли особая техническая причина, почему константы не могут быть собраны во время JIT, а не время компиляции? Существуют ли случаи, когда это может нарушить работу?
Ответы
Ответ 1
Константы должны быть постоянными. За все время. Константы - это такие вещи, как значение pi, или количество протонов в атоме свинца.
Если ваши постоянные изменения, , это не было константой; вместо этого используйте поле readonly.
Также см. Руководство по разработке Framework, в котором указано:
Используйте константные поля для констант, которые никогда не изменятся. Компилятор записывает значения константных полей непосредственно в код вызова. Поэтому константы const никогда не могут быть изменены без риска нарушения совместимости.
По существу, изменение константы без перекомпиляции всего, что от нее зависит, каждый бит сломан, как изменение сигнатуры метода без перекомпиляции всего, что от него зависит. Компилятор "испекает" всевозможные предположения относительно информации о метаданных из ссылочных сборок при компиляции зависимой сборки. Если вы внесете какие-либо изменения, вы не можете ожидать, что вещи просто продолжат работать.
Ответ 2
Существует также третий способ объявить "константы": общедоступное статическое свойство.
public static string ConstString {get{return "First test";}}
У этого есть семантика верности поля только для чтения, но если дрожание встраивает геттер, оно становится постоянной jit-time. И в отличие от const
он может использоваться для определенных пользователем типов.
Я думаю, что неплохо использовать статические свойства для типов значений и строки, но не для пользовательских классов, так как вы не хотите выделять новый экземпляр для каждого доступа к свойствам.
Я использовал это в моем типе FixedPoint следующим образом:
public struct FixedPoint
{
private int raw;
private const fracDigits=16;
private FixedPoint(int raw)
{
this.raw=raw;
}
public static FixedPoint Zero{get{return new FixedPoint();}}
public static FixedPoint One{get{return new FixedPoint(1<<fracDigits);}}
public static FixedPoint MaxValue{get{return new FixedPoint(int.MaxValue);}}
}