Статический readonly vs const - разные сборки POV?

Есть много вопросов по этому вопросу, но никто (кроме один, но все еще короткий) имеет дело со следующим сценарием.

Из книги С# 4:

enter image description here

Марк также написал:

если вы измените значение const, вам нужно перестроить все клиенты

Вопрос:

1) Почему? Имеются значения static readonly и const - static?

2) Где фактически сохраняются значения?

3) Как сделать поле static readonly на самом деле solve этой проблемой "за сценой"?

Ответы

Ответ 1

нет, const является константой, а не статикой - это особый случай с разными правилами; он только установлен во время компиляции (не время выполнения), и обрабатывается по-разному

суть здесь заключается в следующем:

var foo = SomeType.StaticValue;

против

var bar = SomeType.ConstValue;

в первом случае он считывает значение во время выполнения из SomeType, то есть через ldsfld; однако во втором случае это скомпилировано для значения, т.е. если ConstValue оказывается 123, то второй идентичен:

var bar = 123;

во время выполнения, тот факт, что он пришел из SomeType , не существует, поскольку значение (123) было оценено компилятором и сохранено. Следовательно, для восстановления новых значений требуется перестройка.

Переход на static readonly означает, что "загрузить значение из SomeType" сохраняется.

Итак, следующее:

static int Foo()
{
    return Test.Foo;
}
static int Bar()
{
    return Test.Bar;
}
...
static class Test
{
    public static readonly int Foo = 123;
    public const int Bar = 456;
}

компилируется как:

.method private hidebysig static int32 Bar() cil managed
{
    .maxstack 8
    L_0000: ldc.i4 0x1c8
    L_0005: ret 
}

.method private hidebysig static int32 Foo() cil managed
{
    .maxstack 8
    L_0000: ldsfld int32 ConsoleApplication2.Test::Foo
    L_0005: ret 
}

Обратите внимание, что в Bar ldc загружается значение напрямую (0x1c8 == 456), при этом Test полностью уходит.

Для полноты, const реализуется со статическим полем, но - это буквальное поле, означающее: оценивается в компиляторе, а не во время выполнения.

.field public static literal int32 Bar = int32(0x1c8)
.field public static initonly int32 Foo

Ответ 2

если вы измените значение константы, вам нужно перестроить все клиенты

Это не правильное решение. Если вы изменили значение константы, это не было константой. Константы по определению являются вещами, которые никогда не меняют свое значение. Идея о том, что вы измените значение константы, означает, что вы делаете что-то логически невозможное, и, конечно, вещи будут break;, вы делаете то, что вы сказали, что не будете делать. Если вы идете вокруг лжи компилятору, и это больно, когда вы это делаете, то перестаньте лгать компилятору.

Цена золота не постоянна. Название вашего банка не является постоянным. Номер версии вашей программы не является константой. Эти вещи меняются, поэтому не делают их константами. Константы - это такие вещи, как pi, или количество протонов в атоме золота.

Переменные - это вещи, которые могут варьироваться - поэтому их называют "переменными". Константы - это вещи, которые остаются... постоянными. Если он может меняться, сделайте его переменной. Если он постоянный, сделайте его постоянным. Это так просто.

почему? как static readonly, так и const являются статическими

Конечно. Что это имеет к этому отношение? "static" в С# означает "именованный элемент связан с типом, а не с каким-либо конкретным экземпляром типа". ( "Статический", следовательно, является плохим выбором терминов, VB делает это лучше с "общим".)

Независимо от того, связано ли имя с типом или экземпляром, вопрос о том, относится ли это имя к константе или переменной.

где фактически значения сохраняются как в статическом readonly vsconst?

Когда вы используете постоянное значение, значение "испечено" везде, где оно используется. Это безопасно, потому что он никогда не изменится. Он никогда не изменится, потому что он постоянный и что означает "постоянный".

Когда вы используете переменную, значение переменной постоянно просматривается во время выполнения. "readonly" означает "эта переменная может быть изменена только в конструкторе класса или инициализаторе поля". Это по-прежнему переменная. (*)

как сделать поле статическим readonly - на самом деле решить эту проблему за сценой?

Вы не указали, в чем проблема, поэтому я не знаю, какую проблему вы пытаетесь решить.


(*) Поля readonly считаются непостоянными значениями вне конструктора, поэтому поле readonly изменяемого типа значения не может быть мутировано и поэтому вы не можете взять ref в поле только для чтения, а затем изменить ссылка.

Ответ 3

1) const разрешается только во время компиляции со значением, которое вы предоставили. Пока static readonly - статическая переменная.

2) static значения обычно хранятся в специальной области в куче, называемой High Frequency Heap. Как я уже говорил, consts заменяются во время компиляции.

3), сделав его static readonly, решит проблему, потому что вы будете читать значение переменной во время выполнения, а не значение, указанное во время компиляции.

Ответ 4

Вы уже ответили на свой вопрос с изображением, с которым вы связались. Поля const будут скомпилированы ( "inlined" ) в сборку - как простой поиск и замена. static readonly означает нормальное поле, которое не разрешено изменять и существует только один раз в памяти, но по-прежнему ссылается на расположение памяти.

В .NET Framework константам не присваивается область памяти, но вместо этого считаются значениями. Поэтому вы никогда не сможете присвоить константа, но загрузка константы в память более эффективна потому что он может быть введен непосредственно в поток команд. Эта устраняет любые обращения к памяти за пределами памяти, улучшая местность ссылки. http://www.dotnetperls.com/optimization

Ответ 5

Я думаю, мы можем думать о константе как о жестко закодированном значении в нашем коде, но с лучшими предложениями по обслуживанию и удобству использования.