In this article, I shall be discussing about constants and read only fields which we all use in our .NET variant language codes, viz C#, VB .NET, VC++, etc.
Constants are not changeable values in the entire code base once it is defined.
Let's dig a bit deeper into the const keyword which we use in our C# code. Basically, constants are by default/implicitly
static for the scope in which it is defined. Also note that there won't be any memory created for the constants by the run time. So what happens under the hood, let's see via IL and a C# code.
public static void Main(string args)
const int TCPPortNumber = 25;
As you can see from the above image, I have used a constant inside the
main method. Now let's look at the IL (using ILSPY/ILDASM) to see if there is any memory created for the variable or not:
As you can see from the above image, the compiler didn’t create any OpCodes for
TCPPortNumber. Now let's change that variable to non-constant and see the IL:
As you can see from the image, Line 10 block initializes the variable and in line 15 there is a stack memory being created for loading value 25. So this proves that there is no memory created for the constant variables.
Now, you might be wondering that, if no memory is created for constants, then if I use that variable somewhere down the line to do some operation, how or where the run time picks or finds the value.
Let me come back to the same code with constant usage, with a bit of modification as shown:
public class Program
const int TCPPortNumber = 25;
static void Main(string args)
string str = "TCP Port Number is : " + TCPPortNumber);
Since we are appending the constant value to the
string, now the constant variable should get created on memory, right? It looks like that logically atleast. So let's check the IL for the new code then:
As you can see, still the memory for the constant variable is not created by the compiler, but in the usage code the value is directly embedded into IL at line 16.
Another case is, if the constants are defined in another assembly, say
AssemblyA and their usages are in different assembly, say
AssemblyB, after compilation of both assemblies and before run time, you can delete that
AssemblyA which had all constants defined, from the disk and still your usage code runs. So this proves that, at the compilation stage itself, the compiler embeds constant variable’s value everywhere it's been used. So that the CLR won't lookout for the constant variable in memory to refer at run time.
So, as a developer, you should be careful when you are using constants. Assume that you have defined all constants in an assembly
AssemblyA and your usage code is in
AssemblyB. To make it more interesting, the
AssemblyA is developed by a remote team. So whenever
AssemblyA is compiled upon changes to constant values, the same value won't be reflected/embedded into your
AssemblyB code usage by compiler (assuming no usage of strong named assemblies here). To solve this, both assemblies have to be build together upon any changes.
So if you have to overcome this problem, you can use readonly keyword in your production code. Here what happens is, a variable declared as readonly can be defined either at its declaration or in the constructors of the class.
Please note that you can't declare it in any of the methods or ctors because, throughout your class instance life time, the readonly variable should be known and so its value. Hence it is declared in class scope and defined there itself or at object construction AKA ctor. But you can bypass this rule via reflection.
Let's dig a bit deep and see what is happening:
At line 12, the run time shall load the value of
readOnlyVariable from memory.
So every time readonly variable is referred in the usage code, at run time CLR looks up for this variable and gets the value (loading an assembly if it's defined there). Hence a memory is created for readonly variables at run time.
You must note that, here, we are declaring readonly to the variable and not to the memory or the content of the variable. I mean, the meaning of readonly being immutable changes a bit in case of reference type as shown in the below code:
readonly List<string> nameList = new List<string>();
void AddName(string name)
As you can see from the above code, only the variable which is a
ref type here is getting
readonly restriction rules by compiler but not the content of it.
Hope it helps someone.
Thanks & happy coding.