Asked  6 Months ago    Answers:  2   Viewed   22 times

I've read around about const and static readonly fields. We have some classes which contain only constant values. They are used for various things around in our system. So I am wondering if my observation is correct:

Should these kind of constant values always be static readonly for everything that is public? And only use const for internal/protected/private values?

What do you recommend? Should I maybe even not use static readonly fields, but rather use properties maybe?

 Answers

88

public static readonly fields are a little unusual; public static properties (with only a get) would be more common (perhaps backed by a private static readonly field).

const values are burned directly into the call-site; this is double edged:

  • it is useless if the value is fetched at runtime, perhaps from config
  • if you change the value of a const, you need to rebuild all the clients
  • but it can be faster, as it avoids a method call...
  • ...which might sometimes have been inlined by the JIT anyway

If the value will never change, then const is fine - Zero etc make reasonable consts ;p Other than that, static properties are more common.

Tuesday, June 1, 2021
 
o_flyer
answered 6 Months ago
11

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
Monday, August 2, 2021
 
Gaurav
answered 4 Months ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :
 
Share