Difference Between const, readonly, and static in C# (With Examples)
If you’ve spent any time working in C#, you’ve likely come across the keywords const
, readonly
, and static
. They look similar at first glance — all three relate to variables that don’t seem to change much. But under the hood, they work differently and serve distinct purposes.
In this article, we’ll break down the differences between const
, readonly
, and static
in C#, show practical examples, and highlight common mistakes developers make with each one. By the end, you’ll know exactly when to use each keyword in your own code.
What Is const
in C#?
A const
(constant) is a value that is known at compile time and cannot be changed afterward.
Key Points
Must be initialized at the time of declaration.
Value is replaced directly into the compiled code (inlined).
Only certain types can be
const
: numbers,bool
,char
,string
, and enums.Implicitly
static
(no need to mark it asstatic
).
Example
const is meant for values known at compile time and never meant to change
When to Use const
For values that are guaranteed to never change.
For mathematical constants, fixed strings, or settings that never vary.
When performance matters (compiler inlining makes lookup extremely fast).
What Is readonly
in C#?
A readonly
field can only be assigned in two places:
When it’s declared.
In the class constructor.
Unlike const
, a readonly
value is resolved at runtime, not compile time.
Example
readonly is for data that needs to be determined at runtime, but will not change afterwards
When to Use readonly
When the value is fixed after object construction but not known at compile time.
For values that depend on runtime logic (environment, configuration, GUIDs, etc.).
What Is static
in C#?
The static
keyword means that a member belongs to the type itself, not an instance.
Key Points
A
static
field is shared across all instances of a class.A
static
class cannot be instantiated — it can only containstatic
members.Static methods cannot access instance members unless passed an object.
Example
static data belongs to the type itself- not to each instance made from the type
When to Use static
When you need shared state across all objects.
For utility/helper methods (e.g.,
Math.Sqrt()
).To implement singletons or application-wide resources.
Putting It All Together
An example using const, readonly, and static
The following table summarizes what we’ve learned. The “instance or type” row denotes whether the data belongs to the type itself or whether instances constructed from that type each receive their own version of the data.
Summarizing the differences between const, readonly, and static
Performance Notes
One of the subtler differences between these keywords lies in performance and compilation behavior.
const
values are inlined
When you use aconst
, the compiler literally replaces the symbol with the constant value in the compiled IL. This makes lookups extremely fast because there’s no memory indirection — it’s just the value itself. The downside is that changing aconst
requires recompiling every assembly that depends on it.readonly
fields require a lookup
Areadonly
field is stored as part of the object (or type, if declaredstatic readonly
). Accessing it means retrieving a memory reference at runtime. This adds a tiny cost, but it’s usually negligible compared to the safety and flexibility you gain.static
fields are shared in memory
Static fields are created once per application domain and live for the lifetime of the process. This can be more efficient than duplicating values across instances, but it also means you need to be careful about concurrency, as multiple threads may access the same field.
✅ Rule of thumb:
Use
const
when performance is critical and the value will never change.Use
readonly
when correctness and maintainability matter more than shaving nanoseconds.Use
static
when you want to reduce duplication or provide global access.
Common Pitfalls
Here’s where things often go wrong.
1. Confusing const
and readonly
Developers sometimes use const
for values that might change between builds (like API endpoints). This can lead to hard-to-track bugs because consumers compiled against the old constant won’t see the update.
👉 Use readonly
instead for anything that isn’t truly universal and permanent.
2. Using static
for convenience
It’s tempting to make everything static for easy access. But static variables behave like global state. They persist across the entire application, can be modified from anywhere, and can introduce subtle bugs in multithreaded environments.
👉 Avoid overusing static
for things like configuration. Instead, use dependency injection or pass objects explicitly.
3. Thread safety issues with static fields
Static fields are shared, so if multiple threads read/write to them, you can run into race conditions. For example, incrementing a static counter without synchronization can lead to inconsistent results.
👉 If you must use shared state, combine static
with lock
, Interlocked
, or immutable data structures.
4. Over-optimizing for performance
Some developers default to const
because “it’s faster.” While true in theory, the performance difference is negligible in most apps. Choosing the wrong keyword for semantic reasons (e.g., making something const
when it should be readonly
) can cause long-term maintainability issues that far outweigh any speed gain.
👉 Use the keyword that expresses your intent clearly. The compiler and JIT are very good at optimizing.
5. Forgetting that const
is implicitly static
Beginners sometimes try to combine static
with const
:
It’s redundant to add the static qualifier to const
const
is already implicitly static
, so this is unnecessary and won’t compile.
6. Unintended object lifetimes with static references
If you hold large objects in static fields, they’ll live for the duration of the app and won’t be garbage collected. This can lead to memory leaks.
👉 Be intentional when using static
with reference types. If the data is temporary, don’t make it static.
Conclusion
While const
, readonly
, and static
look similar, they solve very different problems:
const
→ compile-time constants, inlined into code, never change.readonly
→ runtime constants, set once at construction, safer for evolving values.static
→ shared across all instances, useful for utilities and global state.
The choice isn’t just about syntax — it’s about performance, maintainability, and correctness. const
can give you tiny speed benefits, but readonly
offers flexibility. static
can cut down on duplication but risks introducing global-state bugs.
By mastering these keywords — and understanding both their power and pitfalls — you’ll avoid subtle bugs, write clearer code, and know exactly when to reach for each tool.