What is the difference between const and readonly in C#?

In C#, both const and readonly are used to create unmodifiable values, but they behave differently in terms of initialization, scope, and usage. Here’s a detailed breakdown of their differences:

1. Initialization

KeywordWhen Value is AssignedExample
constCompile-time constant: Must be initialized at declaration.const int MaxValue = 100;
readonlyRuntime constant: Can be initialized at declaration or in the constructor.readonly string LogPath; (assigned in constructor)

2. Scope

KeywordClass/Instance MemberStatic Behavior
constImplicitly static (belongs to the class). Accessed via ClassName.ConstValue.Math.PI (static by default)
readonlyInstance-level by default. Requires static keyword to behave as a class-level constant.static readonly DateTime StartDate = new DateTime(2023, 1, 1);

3. Supported Types

KeywordAllowed TypesExample
constPrimitive types (int, bool, char, etc.), string, or null references. Cannot be used with most reference types (except string).const string AppName = "MyApp";
readonlyAny type, including reference types (e.g., objects, collections).readonly List<int> Numbers = new List<int>();

4. Memory Behavior

KeywordStorageImplications
constValue is embedded directly into the compiled IL code.No memory allocation at runtime.
readonlyValue is stored in memory as a regular variable.Memory is allocated at runtime.

5. Versioning & Recompilation

KeywordImpact of Value ChangesExample Scenario
constRequires recompilation of all dependent code if the value changes.Changing const int Max = 100 to 200 forces dependent assemblies to rebuild.
readonlyNo recompilation needed. The value is resolved at runtime.Update a readonly config value in a DLL without rebuilding dependent code.

6. Usage Scenarios

KeywordWhen to UseExample Use Case
constValues that never change (e.g., mathematical constants, fixed configurations).const double Pi = 3.14159;
readonlyValues that are determined at runtime but shouldn’t change after object initialization (e.g., dependency-injected settings, calculated values).readonly ILogger _logger; (assigned via constructor injection)

7. Example Code

const Example

public class Calculator
{
    public const double TaxRate = 0.15; // Must be assigned at declaration

    public double CalculateTotal(double price)
    {
        return price * (1 + TaxRate); // Accessed via class name
    }
}

readonly Example

public class AppConfig
{
    public readonly string Environment;
    public static readonly DateTime StartTime = DateTime.Now; // Static readonly

    public AppConfig(string env)
    {
        Environment = env; // Assigned in constructor
    }
}

Key Differences Summary

Featureconstreadonly
InitializationAt declarationDeclaration or constructor
Static by DefaultYesNo (unless static is added)
Supported TypesPrimitives, string, nullAny type
MemoryInlined in IL codeAllocated at runtime
Version SafetyRequires recompilationNo recompilation needed
Use CaseUniversal constantsRuntime-determined values

When to Choose Which?

  • Use const for compile-time constants that are universal and never change (e.g., Math.PI).
  • Use readonly for values determined at runtime or when working with reference types (e.g., configuration settings, injected dependencies).

Leave a Reply

Your email address will not be published. Required fields are marked *