LearnAI ToolsCareerPractice BuildsPlayContact
Lesson 815 min read

Constants

Learn how to declare unchangeable values using const and readonly, and when to reach for each.

What is a Constant?

A constant is a value that cannot change after it is set — useful for things that are fixed by definition (the value of pi), by business rule (a tax rate), or by convention (an application's name). C# provides two distinct ways to declare one: `const` and `readonly`, and despite both meaning "unchangeable," they behave quite differently under the hood.

const

A `const` value must be known at compile time — meaning it has to be a literal or a simple expression the compiler can fully evaluate while building your program, never something computed at runtime. It is implicitly static, meaning it is shared across the whole type rather than belonging to any one object instance, and you never write the static keyword yourself for a const.

const double Pi = 3.14159;
const string AppName = "PrograMinds";
const int MaxRetries = 3;
// Simple expressions using other consts are allowed:
const int SecondsPerMinute = 60;
const int SecondsPerHour = SecondsPerMinute * 60; // fine — fully computable at compile time
What const Cannot Do

const CANNOT be used for anything whose value is only known while the program is running — a value read from a database, a configuration file, user input, or even DateTime.Now, since none of these are knowable at compile time. Attempting this produces a compile error.

readonly

A `readonly` field can be assigned either at declaration or inside a constructor, but never changed afterward. Unlike const, its value can be computed at runtime — this makes it useful for values that vary per object but shouldn't change once that particular object is created.

class Account
{
public readonly string AccountId;
public readonly DateTime CreatedAt;
public Account(string id)
{
AccountId = id; // allowed inside constructor
CreatedAt = DateTime.Now; // runtime value — impossible with const
}
}
var account = new Account("ACC-001");
Console.WriteLine(account.AccountId); // ACC-001
// account.AccountId = "ACC-002"; // ❌ compile error — readonly fields can't be reassigned

static readonly

Combining static and readonly gives you a value that is shared across every instance of a class (like const) but can still be computed at runtime (unlike const) — the closest thing to "the best of both worlds" for values that are fixed once, at startup, but can't be known purely at compile time.

class AppConfig
{
public static readonly string StartupTime = DateTime.Now.ToString();
public static readonly Guid InstanceId = Guid.NewGuid();
}

const vs readonly

constreadonlystatic readonly
Value known atCompile time onlyCompile time or runtimeCompile time or runtime
Can be set in constructorNoYesNo (only at declaration or a static constructor)
Shared across instancesYes (implicitly)No (per-instance)Yes (explicitly static)
Can hold a computed/runtime valueNoYesYes

Real-World Example: A Configuration Class

A realistic example combining all three, showing exactly when each one is the right tool.

class AppSettings
{
// True mathematical/logical constant — never changes, ever, for any app
public const int MaxUsernameLength = 20;
// Fixed at startup, but computed at runtime — can't be a const
public static readonly DateTime ApplicationStartedAt = DateTime.Now;
// Varies per instance, set once in the constructor
public readonly string Environment;
public AppSettings(string environment)
{
Environment = environment;
}
}
var devSettings = new AppSettings("Development");
var prodSettings = new AppSettings("Production");
Console.WriteLine(devSettings.Environment); // Development
Console.WriteLine(prodSettings.Environment); // Production
Console.WriteLine(AppSettings.MaxUsernameLength); // 20 — same for both, accessed via the class, not an instance

Common Beginner Mistakes

Trying to use const for a runtime-computed value

const DateTime Now = DateTime.Now; will not compile — DateTime.Now can only be known while the program runs, never at compile time. Use static readonly instead.

Trying to assign a readonly field outside its constructor

Once construction finishes, a readonly field is locked — attempting to change it anywhere else, even in another method of the same class, is a compile error.

Assuming const is always safer than readonly

A const baked into a compiled library requires recompiling every consumer of that library if the value ever changes; a static readonly value can be updated by simply rebuilding the one library, without breaking binary compatibility for its consumers — a subtle but real distinction in library design.

FAQs

Use `const` for true, fixed values like mathematical constants or a hard limit that will genuinely never change. Use `readonly` for values that depend on runtime input, like an ID passed into a constructor, or `static readonly` for a runtime-computed value shared across every instance.

Only string and null are allowed as reference-type consts — any other reference type (like a custom class or an array) cannot be a const, since the compiler can't guarantee its contents are truly fixed at compile time.

No — readonly only prevents reassigning the field itself to a different object; if the field holds a mutable object (like a List<T>), the contents of that object can still be changed freely, just not swapped for an entirely different object.

const is technically faster since its value is baked directly into the compiled code at every usage site (no memory lookup needed), but this difference is utterly negligible for the vast majority of real applications.

Key Takeaways

  • `const` values are fixed at compile time, implicitly static, and can only be primitives, strings, or null.
  • `readonly` values can be set in a constructor (allowing runtime computation) but not changed afterward.
  • `static readonly` combines runtime computation with being shared across every instance of a class.
  • Choose based on whether the value is truly fixed forever (const), varies per instance but set once (readonly), or fixed once but shared and computed at runtime (static readonly).

Summary

const, readonly, and static readonly give you three distinct flavors of "unchangeable," each suited to a different scenario — knowing which to reach for is a small but genuinely useful piece of professional C# judgment. Next, you'll explore C#'s full range of built-in data types.

Next Lesson →

Data Types