In C#, readonly and const are both used to define immutable values, but they have key differences in how and when their values are assigned.
- const (Constant)
- A const field is a compile-time constant, meaning its value must be assigned at declaration and cannot be changed later.
- It is implicitly static, so it belongs to the type rather than an instance.
- The value of a const field is hardcoded into the compiled code, so changes require recompilation.
- Only primitive types, enums, and string can be const.
Example of const:
class Example {
public const double Pi = 3.14159; // Must be assigned at declaration
}
Example. Pi is a compile-time constant and cannot be changed.
- readonly (Read-Only Field)
- A readonly field can be assigned only during declaration or in the constructor, making it a runtime constant.
- It is not implicitly static, so each instance can have different values.
- Unlike const, readonly fields can hold reference types and mutable objects (though the reference itself remains immutable).
- It is evaluated at runtime, meaning it can be set dynamically based on constructor parameters.
Example of readonly:
class Example {
public readonly int number; // Value can be set in constructor
public Example(int value) {
number = value; // Allowed in constructor
}
}
Each instance of Example can have a different number value.
Key Differences:
Feature | const | readonly |
Assignment | Only at declaration | At declaration or in constructor |
Mutability | Cannot change after compilation | Can be assigned per instance in the constructor |
Storage | Stored as a literal in compiled code | Stored in memory like normal fields |
Type Support | Only primitive types, enums, and strings | Any data type (value or reference) |
Instance vs. Static | Always static | Can be instance or static |
Runtime Evaluation | No (compile-time only) | Yes (runtime assignment allowed) |
When to Use Which?
- Use const when the value is truly constant (e.g., mathematical constants like Pi, conversion factors).
- Use readonly when the value can be determined at runtime (e.g., configuration settings, object references).