DekGenius.com
[ Team LiB ] Previous Section Next Section

Recipe 3.25 Initializing a Constant Field at Runtime

Problem

A field marked as const can be initialized only at compile time. You need to initialize a field at runtime to a valid value, not at compile time. This field must then act as if it were a constant field for the rest of the application's life.

Solution

When declaring a constant value in your code, there are two choices. You can use a readonly field or a const field. Each has its own strengths and weaknesses. However, if you need to initialize a constant field at runtime, you should use a readonly field:

public class Foo
{
    public readonly int bar;

    public Foo( ) {}

    public Foo(int constInitValue)
    {
        bar = constInitValue;
    }

    // Rest of class...
}

This is not possible using a const field. A const field can be initialized only at compile time:

public class Foo
{
    public const int bar;        // This line causes a compile-time error

    public Foo( ) {}

    public Foo(int constInitValue)
    {
        bar = constInitValue;    // This line also causes a compile-time error
    }

    // Rest of class...
}

Discussion

A readonly field allows initialization to take place only in the constructor at runtime, whereas a const field must be initialized at compile time. Therefore, implementing a readonly field is the only way to allow a field that must be constant to be initialized at runtime.

There are only two ways to initialize a readonly field. The first is by adding an initializer to the field itself:

public readonly int bar = 100;

The second way is to initialize the readonly field through a constructor. This is demonstrated through the code in the Solution to this recipe.

If you look at the following class:

public class Foo
{
        public readonly int x;
        public const int y = 1;

        public Foo( ) {}

        public Foo(int roInitValue)
        {
        x = roInitValue;
        }

        // Rest of class...
}

You'll see it is compiled into the following IL:

.class public auto ansi beforefieldinit Foo
    extends [mscorlib]System.Object
{
.field public static literal int32 y = int32(0x00000001)  //<<-- const field
.field public initonly int32 x                            //<<-- readonly field
.method public hidebysig specialname rtspecialname 
        instance void  .ctor(int32 input) cil managed
{
    // Code size       14 (0xe)
    .maxstack  8
//001659:         }
//001660: }

//001666: public class Foo
//001667: {
//001668:         public readonly int x;
//001669:         public const int y = 1;
//001670:         
//001671:         public Foo(int roInitValue)
    IL_0000:  ldarg.0
    IL_0001:  call       instance void [mscorlib]System.Object::.ctor( )
//001672:         {
//001673:                 x = input;
    IL_0006:  ldarg.0
    IL_0007:  ldarg.1
    IL_0008:  stfld      int32 Foo::x
//001674         }
    IL_000d:  ret
} // end of method Foo::.ctor

} // end of class Foo

Notice that a const field is compiled into a static field, and a readonly field is compiled into an instance field. Therefore, you need only a class name to access a const field.

A common argument against using const fields is that they do not version as well as readonly fields. If you rebuild a component that defines a const field, and the value of that const changes in a later version, any other components that were built against the old version won't pick up the new value.


The following code shows how to use a readonly field:

Foo obj1 = new Foo(100);
Console.WriteLine(obj1.bar);

Those two lines compile into the following IL:

IL_0013:  ldc.i4     0xc8
IL_0018:  newobj     instance void Foo::.ctor(int32)
IL_001d:  stloc.1
IL_001e:  ldloc.1
IL_001f:  ldfld      int32 Foo::bar

Since the const field is already compiled into the application as a static member field, only one simple IL instruction is needed to use this const field at any point in the application:

IL_0029:  ldc.i4.1

Notice that the compiler compiled away the const field and uses the value it was initialized to, which is 1. This is faster than using a readonly field. However, const fields are inflexible as far as versioning is concerned.

See Also

See the "const" and "readonly" keywords in the MSDN documentation.

    [ Team LiB ] Previous Section Next Section