There are many questions about this subject , but none (except one but still a short one) are dealing with the following scenario.
From C# 4 book:
Marc also wrote :
if you change the value of a const, you need to rebuild all the
clients
Question :
1) Why is that? Are both static readonly
and const
— static
?
2) Where actually the values are saved ?
3) How does making a field static readonly
actually solve
this problem "behind the scene" ?
no, a const is a const, not a static - it is a special-case, with different rules; it is only set at compile-time (not runtime), and it is handled differently
the crux here is what the following means:
var foo = SomeType.StaticValue;
vs
var bar = SomeType.ConstValue;
in the first case, it reads the value at runtime from SomeType
, i.e. via a ldsfld
; however, in the second case, that is compiled to the value, i.e. if ConstValue
happens to be 123
, then the second is identical to:
var bar = 123;
at runtime, the fact that it came from SomeType
does not exist, as the value (123
) was evaluated by the compiler, and stored. Hence it needs a rebuild to pick up new values.
Changing to static readonly
means that the "load the value from SomeType
" is preserved.
So the following:
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;
}
compiles as:
.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
}
Note that in the Bar
, the ldc
is loading a value directly (0x1c8 == 456), with Test
completely gone.
For completeness, the const is implemented with a static field, but - it is a literal field, meaning: evaluated at the compiler, not at runtime.
.field public static literal int32 Bar = int32(0x1c8)
.field public static initonly int32 Foo
if you change the value of a const, you need to rebuild all the clients
That is not the correct solution. If you change the value of a const then it was not a constant. Constants are by definition things that never change their value. The idea that you would change the value of a constant means that you are doing something logically impossible, and so of course things will break; you're doing something that you said you would not do. If you go around lying to the compiler, and it hurts when you do that, then stop lying to the compiler.
The price of gold is not a constant. The name of your bank is not a constant. The version number of your program is not a constant. These things change, so do not make them constants. Constants are things like pi, or the number of protons in an atom of gold.
Variables are things that can vary -- that's why they're called "variables". Constants are things that stay... constant. If it can vary, make it a variable. If it is constant, make it a constant. It is as simple as that.
why is that? both static readonly and const are static
Sure. What does that have to do with it? "static" in C# means "the named element is associated with the type, rather than with any particular instance of the type." ("Static" is therefore a poor choice of terms; VB does it better with "shared".)
Whether the name is associated with the type or an instance is irrelevant to the question of whether the name refers to a constant or variable.
where actually the values is being saved in both static readonly vsconst ?
When you use a constant value, the value is "baked in" wherever it is used. That's safe because it is never going to change. It's never going to change because it is constant, and that's what "constant" means.
When you use a variable, the variable's value is looked up at runtime every time. "readonly" just means "this variable can only be changed in the class constructor or field initializer". It is still a variable. (*)
how making a field static readonly - actually solve this problem behind the scene ?
You haven't stated what the problem is, so I don't know what problem you're trying to solve.
(*) Readonly fields are considered to be non-constant values outside the constructor, so that a readonly field of mutable value type cannot be mutated, and so that you cannot take a ref
to a readonly field and then mutate the reference.
1) const
is just resolved during compile time with the value that you have provided. While static readonly
is a static variable.
2) static
values are usually stored on a special area on the heap called High Frequency Heap. As I said previously consts are substituted at compile time.
3) making it static readonly
will solve the problem because you will be reading a variable value at runtime, not a value provided at compile time.
You have already answered your question with the image you linked to. const
fields will be compiled ("inlined") into the assembly - like a simple search and replace. static readonly
means a normal field that is not allowed to change and exists only once in memory, but is still referenced by memory location.
In the .NET Framework, constants are not assigned a memory region, but
are instead considered values. Therefore, you can never assign a
constant, but loading the constant into memory is more efficient
because it can injected directly into the instruction stream. This
eliminates any memory accesses outside of the memory, improving
locality of reference. http://www.dotnetperls.com/optimization
I guess we can think of a constant as a hardcoded value in our code, but with better maintenance and usability offerings.