'const' vs 'static readonly'

I'm a big fan of reusing code whenever and wherever possible.  A long time ago, I wrote an assembly that provided common methods and data to some applications I was writing.  When I first wrote the assembly, I exposedthe common data as public fields decorated with the const keyword, as shown in the example below.

public class HelperData{    public const Int32 Iterations = 5;}

When I used the field, in my application, I saw the expected results, and checked in my code.

The value of HelperData.Iterations is 5

Later, I needed to update my application (increase the number of iterations), so remembering that I had put the iteration count in my helper assembly, I changed the code and deployed the new dll.  When I ran my application, the iteration count did not change, it was still using the old value (5).  Scratching my head, I tried building and deploying my dll again with the exact same result.

When I looked at my application's IL, I found my problem.

ldstr "The value of HelperData.Iterations is "ldc.i4.5

When my application was built, the literal value (5) of the HelperData.Iterations field was compiled into the executable (ldc.i4.5).  My application used the original value because it was never actually referencing the field in the helper assembly.  This made sense once I thought about it.  Because I had defined my field as a constant, the compiler optimized away the assembly reference.

To fix the problem (I really did want the assembly reference), I changed my helper class to expose Iterations as a static readonly field.

public class HelperData{    public static readonly Int32 Iterations = 5;}

After rebuilding the application referencing the updated assembly, I see my expected output.

The value of HelperData.Iterations is 5

When I change the value of Iterations (to 43), rebuild and update just the helper assembly, my application reflects the update.

The value of HelperData.Iterations is 43

Examining the IL shows why. 

ldstr "The value of HelperData.Iterations is "ldsfld int32 [Helper]Helper.HelperData::Iterations

Instead of compiling in the literal value, as was done above, we now see that the IL instructions are loading the field value from the helper assembly (ldsfld int32 [Helper]Helper.HelperData::Iterations).

Enjoy!
-- DK

Disclaimers:
This posting is provided "AS IS" with no warranties, and confers no rights.

Comments

  • Anonymous
    October 30, 2006
    usefull article Thank You

  • Anonymous
    November 29, 2006
    What do you think about this variation? It does the same thing but without the need to explain readonly vs const every time someone comes across the other version. public class HelperData {    public static Int32 Iterations {get { return 5}; } Emma

    David Kline: This is a valid variation as well.  My preference is to use a static readonly field to avoid the overhead of a the method call.

  • Anonymous
    December 28, 2006
    I started this series last year and thought I would continue the tradition with my best of 2006 collection.