Recipe3.24.Initializing a Constant Field at Runtime


Recipe 3.24. 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 to a valid value at runtime, 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

You have two choices when declaring a constant value in your code. 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 must 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 an instance 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.



C# Cookbook
Secure Programming Cookbook for C and C++: Recipes for Cryptography, Authentication, Input Validation & More
ISBN: 0596003943
EAN: 2147483647
Year: 2004
Pages: 424

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net