Const and readonly (fields) in C#
These are the most commonly used and confused keywords in .NET framework. This article briefly explains both of the keywords and explains them in the scenarios they can be used in.
Constants
As the name suggests the const keyword can be used to set the value of a field at compile time. We need to provide the value to the const field when it is defined. The compiler then saves the constant's value in the assembly's metadata. This means that a constant can be defined only for the primitive type like boolean, char, byte and so on. Constants are always considered static members, not instance members. If we have not provided the value, we get the compile time error “A const field requires a value to be provided”. To support our belief that constant is stored in the metadata I have defined a class with a constant named myConstant as in the following.
- public class DisplayClass
-
- {
-
- public const int myConstant = 10;
-
- }
Now if I look into the metadata of the class using the ildasm I will get the following result:
This shows that the value of the constant is stored in the metadata for the class. When the code refers to a constant symbol, the compiler looks up the symbol in the metadata of the assembly that defines the constant, extracts the constant's value and embeds the value in the emitted IL code. This is the reason constants don't require any memory at runtime to be allocated for themselves and since we don't have any memory for the constant that is why these can't be passed as reference.
To show that the value is embedded in the IL code of the application when it refers to an assembly that contains a constant. I have created an assembly as shown below.
- namespace ReferencedAssembly
-
- {
-
- public class DisplayClass
-
- {
-
- public const int myConstant = 10;
-
- }
-
- }
Now I will refer to this assembly in my application as shown below.
- class Program
-
- {
-
- static void Main(string[] args)
-
- {
-
- Console.WriteLine("My Constant defined in the library:" + DisplayClass.myConstant);
-
- }
-
- }
Now if I build and compile my application and check the IL code using the ildasm as shown below, we can see that the myConstant's value is embedded in the code. Even if we delete the referenced assembly, it will not have any impact on my application.
By now we should have gotten the point that constants can cause some serious versioning problems. If the developer of the Referenced assembly only builds and compiles this assembly and not the application, the application would still refer to the old constant's value. If we want to choose the new value for the constant then in that case we need to recompile our application as well. To choose the latest value we can change it to readonly that I will discuss next. From our discussion we can come to the conclusion that the constant can be used only and only if we are sure that we will not be changing its value in the future.
Fields
Fields can be instance, static and readonly. For a type field (static), the dynamic memory required to hold the field's data is allocated inside the type object that is created when the type is loaded into the AppDomain. That typically happens the first time a method references the type is JIT compiled. For instance fields and the dynamic memory to hold the field is allocated when an instance of the type is constructed.
Since the fields are stored in the dynamic memory, their value can be obtained at runtime only. The versioning problem that we checked in the last section can be resolved by using fields. Apart from that, fields can be any data type, unlike constants that can only be primitive types.
Readonly fields can only be resolved at runtime. That means we can define a value for a value using the constructor for the type in which the field is declared. The verification is done by the compiler that readonly fields are not written to by any method other than the constructor. But please note that reflection can be used to modify a readonly field but that is out of the scope of this article.
Now suppose I use a readonly field in the assembly that I defined earlier.
- public class DisplayClass
-
- {
-
- public const int myConstant = 10;
-
- public readonly int myReadOnly;
-
- public DisplayClass()
-
- {
-
- myReadOnly = 20;
-
- }
-
- }
And I change my application code as in the following to use the readonly field, now when the application's main method runs, the CLR will load the DLL assembly. That means that my assembly is required at run time and grabs the value of myReadOnly as 20 out of the dynamic memory allocated for it.
- static void Main(string[] args)
-
- {
-
- Console.WriteLine("My Constant defined in the library:" + DisplayClass.myConstant);
-
- Console.ReadLine();
-
- DisplayClass display = new DisplayClass();
-
- Console.WriteLine("My readonly field defined in the library:" + display.myReadOnly);
-
- }
Now suppose I change the value of myReadOnly field to 30, in that case we only need to rebuild only the assembly and not the application. Though we need to keep the point in mind that the assembly is not strongly named and the versioning policy of the application helps the CLR to load this new version.
Kindly share your thoughts about the article.