Use ReadOnly Instead of Constants in C#

There are two types of constants available in C#, those are compile-time constants and run-time constants. We can declare run-time constants with readonly keyword and compile-time constants with const keyword.  Each of these constants has different purpose, using wrong one at wrong place will cost you. In C#, most of the time we should use run-time constants instead of compile-time constants because run-time constants are very much flexible as compared with compile-time constants. Compile-time constants are slightly faster; so, where performance is critical, use compile-time constants instead of run-tie constants.

Declare run-time constants (using readonly) and compile-time constants (using const) keyword as shown below. Here I am using Microsoft Visual Studio 2017.

//compile-time constants

public const int MaxValue = 10000;

 

//run-time constants

public readonly int Max_Value = 10000;

We can declare compile-time constants at class or struct scope and can also declare in methods. But run-time constants can be declared only at class or struct level.

The main difference between compile-time constants and run-time constants is, after compilation that means when your code compiles to MSIL (Microsoft Intermediate Language) compile-time constant is replaced with value whereas run-time constant replaced with read-only variable only, not with value. For example, the above code converted into MSIL as below after compilation.

If we assign compile-time constant like int iMax = MaxValue; then it converts to MSIL code as int iMax = 10000; after compilation.

If we assign run-time constant like int iMax = Max_Value; then its MSIL code also same as int iMax = Max_Value; after compilation.

Compile-time constants used for only built-in integral and floating types, enums, and strings. These types can be replaced with values at compile time. We cannot initialize compile-time constant using the new operator. For example, the below code produces the compile time errors.

//compile-time constants

public const DateTime Dt_Time = new DateTime(2018, 4, 15);

Compile-time constants are limited to numbers, strings, and null. We cannot modify the compile-time constants values after initialization.

Run-time constants can be any type, even you can initialize run-time constants by using new operator as shown below.

//run-time constants

public readonly DateTime Dt_Time = new DateTime(2018, 4, 15);

We can assign value to run-time constants at the time of declaration and we can also change the value in constructors as below.

class Employee

{

        //compile-time constants

        public const int MaxValue = 10000;

 

        //run-time constants

        public readonly int Max_Value = 10000;

 

        Employee()

        {

            //produces compile-time errors

            MaxValue = 20000;

 

            //No errors

            Max_Value = 20000;

        }

}

Run-time constants are very much flexible as compared with compile-time constants when your constants are getting used from different assemblies. For example, we have assembly Assembly1 with run-time and compile-time constants as below.

using System;

 

namespace Assembly1

{

    public class Company

    {

        //compile-time constants

        public const int MaxValue = 10000;

 

        //run-time constants

        public readonly int Max_Value = 10000;

    }

}

 

Build this assembly and add reference for Assembly1 to your application. Display constants values from Assembly1 in your application as below.

using Assembly1;

using System;

 

namespace ConsoleApp1

{

    class Program

    {

        static void Main(string[] args)

        {

            Console.WriteLine(Company.MaxValue); //Compile-time constants

            Console.WriteLine(Company.Max_Value); //run-time constants

 

            Console.ReadLine();

        }

    }

}

 

Run the application, it displays the output as below.

Now, change the constants values to 20000 in Assembly1 and build it as below.

using System;

 

namespace Assembly1

{

    public class Company

    {

        //compile-time constants

        public const int MaxValue = 20000;

 

        //run-time constants

        public static readonly int Max_Value = 20000;

    }

}


 

Replace Assembly1.dll in your application. Run your application, it displays the output as below.

As shown above, compile-time constant value didn’t get changed whereas run-time constant value changed. Its because MSIL places value for compile-time constants and variable for run-time constants. That’s why if run-time constant value changes, it replaces old value with new value where ever it is used, and it will not happen same with compile-time constants.

You can use compile-time constants instead of run-time constants where performance is very critical. At all other places use run-time constants for more flexibility.