22 November 2011

Be Careful of Constant fields in .NET

We all know that Constant fields are those whose value never changes in the lifetime of an application. Constant are really useful constructs that offer many benifits to the user like,
  • Constants make developer sure that their value never changes (even by mistake).
  • Constants are compile time values, which means their values are directly embedded inside the metadata. Hence, constants don't require memory allocation at runtime.
All that said, there is a risk in using the constants if appropriate care is not taken. See the second point above - "constant values are embedded directly inside the metadata". This statement has an impact when you have constant fields in a DLL which are used in one or more applications. Let me start demostrating you through a sample code. Consider that the below class exists in a library called MyLibrary.DLL.

public class GlobalConstants
    public const Int32 MAX_VALUE = 2;
    public const String MALESTRING = "Male";
    public const String FEMALESTRING = "Female";

Now, I have to use GlobalConstants in my application. For that I will create a Console Application called SampleClient.exe. Inside the Main function I use the above constants as

class Program
    static void Main(string[] args)
        int maxValue = GlobalConstants.MAX_VALUE;
        String Female = GlobalConstants.FEMALESTRING;


Build SampleClient.exe and run it directly from bin folder. Your application will print 2  and Female as expected and everything is fine. Now I got a requirment that MAX_VALUE should be changed to 100, MALE should be "Man" and FEMALE should change to "Woman". Ok, thats fine. I will update GlobalConstants in MyLibrary.DLL class as below.

public class GlobalConstants
    public const Int32 MAX_VALUE = 100;
    public const String MALESTRING = "Man";
    public const String FEMALESTRING = "Woman";

I will re-build MyLibrary.DLL and send the dll for use in SampleClient.exe. So, place the new dll in bin folder of SampleClient and run it. SampleClient is now refering to new MyLibrary.DLL. But what output do you see? you expect that it will print 100 and Woman but it still prints 2 and Female. So, what is the problem? For that you need to see the IL code of Main method in SampleClient.

Observe that the values 2 and FEMALE are hardcoded in the IL. Though you have changed MAX_VALUE to 100 & FEMALE to "Woman", the values are not reflected. To correct this problem, you must re-build SampleClient application too to make use of new constant value in the dll. Rebuilding SampleClient will embed the new MAX_VALUE and FEMALE values into metadata of Main method.

With this problem, consider your DLL is consumed by Hundreds of applications. So, changing a constant value in your library will result in rebuilding of all it's consumers. So, be careful with constants, use them only when you are sure that their value never-ever change or if they change, you afford re-building it's consumers. Or, if you think constant values may change, then prefer using 'readonly' fields over constants. I will discuss about 'readonly' fields in my next writing.