DEV Community

Libin Tom Baby
Libin Tom Baby

Posted on

Difference Between 'const' and 'readonly' in C# — The Definitive, Practical Guide


Difference Between const and readonly in C#

If you’ve been writing C# for a while, you’ve definitely used both const and readonly. They look similar, they both represent “values that shouldn’t change,” and they both help make your code safer.

But under the hood, they behave very differently — and choosing the wrong one can lead to bugs, versioning issues, and unexpected runtime behavior.

This guide breaks down the differences with definitions, examples, IL behavior, performance notes, and real-world scenarios.


What Is const?

const defines a compile-time constant.

Key characteristics

  • Value is baked into the assembly at compile time
  • Must be assigned at declaration
  • Only supports primitive types + string
  • Cannot be changed
  • Faster access (inlined)
  • Changing a const in a library requires recompiling all dependent projects

Example

public const int MaxItems = 100;
Enter fullscreen mode Exit fullscreen mode

This value is fixed forever at compile time.


What Is readonly?

readonly defines a runtime constant.

Key characteristics

  • Value is assigned at runtime
  • Can be set in:
    • Declaration
    • Constructor
  • Supports any type (objects, lists, structs, etc.)
  • Not inlined — stored in memory
  • Changing a readonly value in a library does NOT require recompilation of consumers

Example

public readonly int MaxItems;

public MyClass()
{
    MaxItems = 100;
}
Enter fullscreen mode Exit fullscreen mode

Side‑by‑Side Comparison

Feature const readonly
When value is set Compile-time Runtime
Can be changed later ❌ No ❌ No (after construction)
Allowed types Primitives + string Any type
Assigned in constructor ❌ No ✔️ Yes
Inlined by compiler ✔️ Yes ❌ No
Requires recompilation of dependent assemblies ✔️ Yes ❌ No
Use for Fixed values Configurable runtime values

IL (Intermediate Language) Behavior

const

Compiler replaces all references with the literal value.

ldc.i4.s 100
Enter fullscreen mode Exit fullscreen mode

readonly

Compiler loads the field at runtime.

ldfld int32 MyClass::MaxItems
Enter fullscreen mode Exit fullscreen mode

This is why changing a const in a shared library can break consumers — they still hold the old literal value.


Real‑World Scenarios

Scenario 1: Mathematical constants

Use const.

public const double Pi = 3.14159;
Enter fullscreen mode Exit fullscreen mode

These values never change.


Scenario 2: API base URLs

Use readonly.

public static readonly string BaseUrl = 
    Environment.GetEnvironmentVariable("API_URL");
Enter fullscreen mode Exit fullscreen mode

This value depends on environment — cannot be const.


Scenario 3: Configuration values

Use readonly.

public readonly int CacheDuration;

public Settings(int duration)
{
    CacheDuration = duration;
}
Enter fullscreen mode Exit fullscreen mode

Scenario 4: Versioning

If you expose constants in a shared library:

public const int Timeout = 30;
Enter fullscreen mode Exit fullscreen mode

And later change it to:

public const int Timeout = 60;
Enter fullscreen mode Exit fullscreen mode

All dependent projects must be recompiled or they will still use 30.

Use readonly instead.


Interview‑Ready Summary

  • const = compile-time constant
  • readonly = runtime constant
  • const is inlined; readonly is stored in memory
  • const only supports primitive types + string
  • readonly supports any type
  • Use const for values that never change
  • Use readonly for values that may vary per environment or runtime

Top comments (0)