C# Variables and Constants: var, const and readonly Explained
Storing data that changes — and data that stays the same — in C#.
Imagine you're building a calculator app. You need to store the numbers the user enters, the result of each operation, and maybe a fixed value like PI that never changes. Every time the user presses a button, the numbers in memory change — but PI stays exactly the same.
That's the core difference between variables and constants in C#. Variables hold data that can change as your program runs. Constants hold data that stays fixed forever.
Every C# program — from a simple console app to a massive enterprise system — uses variables and constants constantly. Understanding them is the first step toward writing real code that works with data.
What Is It?
The Simple Explanation
Variable = A named storage location in memory whose value can change during program execution.
Constant = A named storage location whose value is fixed at compile time and cannot change afterward.
The Technical Definition
Variables are named memory locations that store values. You declare a variable by specifying its type and name, and you can assign a value to it. The value can be changed any number of times during the program's lifetime.
Constants are values that are known at compile time and do not change for the entire lifetime of the program. They are declared using the const keyword and must be assigned a value at declaration. The compiler replaces constant references with their literal values during compilation.
Why Does It Exist?
The Problem
When you write a program, you need to work with data. A user's name, a bank balance, the current time, a product price — these are all pieces of information your program needs to store, retrieve, and manipulate.
Imagine if you had to remember the memory address of every piece of data you used. It would be nearly impossible to write any program larger than "Hello, World!"
The Solution
Variables give you a named way to refer to data. Instead of remembering that the user's age is at memory address 0x7FFD8A3F9C10, you can simply use the name age. Constants give you a way to give meaningful names to fixed values — so instead of writing 3.14159 everywhere, you write PI.
Variables and constants are how your program "remembers" data. Without them, every piece of information would have to be re-entered or recalculated every time it was needed.
Big Picture
Here's how variables and constants fit into the C# type system and memory:
- Store data directly on the stack
- Examples:
int,bool,double,struct
- Store a reference on the stack, data on the heap
- Examples:
string,object,class,array
const)
- Inlined by the compiler — no memory allocation at runtime
- Only value types and
stringcan beconst - Must be assigned at declaration
readonly)
- Assigned at declaration or in the constructor
- Can be reference types
- Not inlined — accessed like a field
How It Works
Let's trace what happens when you declare and use variables and constants in C#:
Step 1 — Declare a variable
int age; // Declaration — memory is reserved, but no value is set yet
You tell the compiler: "I need a storage location named age that can hold an int." The compiler reserves memory for it.
Step 2 — Initialize the variable
age = 25; // Assignment — the value 25 is stored in the reserved memory
You write a value into the memory location. Now age holds the value 25.
Step 3 — Declare and initialize a constant
const double PI = 3.14159; // Must be assigned at declaration
The compiler sees PI and replaces every use of PI with 3.14159 at compile time. No memory is allocated at runtime.
Step 4 — Use the variable and constant
double circumference = 2 * PI * radius; // PI is replaced with 3.14159
The variable radius holds a value from user input or calculation. The constant PI provides the fixed mathematical value.
Simple Example
Here's a complete C# program showing variables and constants in action:
// ── Variables ──
string userName = "Alice"; // Can change later
int score = 0; // Starts at 0, can increase
bool isGameOver = false; // Tracks game state
// ── Constants ──
const int MAX_SCORE = 100; // Fixed maximum
const string GAME_TITLE = "Super C# Adventure";
// ── Using them ──
Console.WriteLine($"Welcome to {GAME_TITLE}, {userName}!");
score += 10; // Variable changes
if (score >= MAX_SCORE) // Constant used in condition
{
isGameOver = true;
Console.WriteLine($"You win, {userName}!");
}
What's happening:
userName,score,isGameOverare variables — their values can change as the game progresses.MAX_SCOREandGAME_TITLEare constants — their values are fixed and known at compile time.- The variable
scorestarts at 0 and increases by 10 each time the player scores. - The constant
MAX_SCOREsets the winning threshold — it never changes.
Real-World Example
Consider an e‑commerce checkout system. Here's how variables and constants would be used:
// ── Constants (business rules that never change) ──
const decimal TAX_RATE = 0.08m; // 8% sales tax
const decimal FREE_SHIPPING_THRESHOLD = 50.00m;
const decimal STANDARD_SHIPPING = 5.99m;
// ── Variables (data that changes per order) ──
string customerName = "Jane Doe";
var cartItems = new List<Product>(); // C# 14: collection expression
decimal subtotal = 0.00m;
decimal tax = 0.00m;
decimal shipping = 0.00m;
decimal total = 0.00m;
// ── Calculate order totals ──
foreach (var item in cartItems)
{
subtotal += item.Price * item.Quantity; // Variable changes
}
tax = subtotal * TAX_RATE; // Constant used
if (subtotal >= FREE_SHIPPING_THRESHOLD) // Constant used
{
shipping = 0.00m;
}
else
{
shipping = STANDARD_SHIPPING; // Constant used
}
total = subtotal + tax + shipping; // Final variable
// ── Output ──
Console.WriteLine($"Order for {customerName}: ${total:F2}");
What's happening:
- Constants (
TAX_RATE,FREE_SHIPPING_THRESHOLD,STANDARD_SHIPPING) represent fixed business rules that rarely change. - Variables (
customerName,subtotal,tax,shipping,total) hold data specific to each order. - If the tax rate changes, you update the constant in one place — not every calculation.
- If the free shipping threshold changes, you change the constant and every order uses the new value.
Analogy
You have a box with a label — age. You can put a number in it, take it out, and replace it with a different number later. The box stays the same; the contents change.
You have a plaque with PI = 3.14159 engraved into it. You can read it, but you can never change it. The value is fixed forever.
- Label = The variable name (
age,score,subtotal) - Box contents = The value stored (
25,0,42.50) - Engraved plaque = The constant (
MAX_SCORE,PI) - Reading the plaque = Using the constant in your code
- Trying to change the plaque = Compiler error — you can't reassign a constant
Under the Hood
Let's look at what actually happens in memory and at compile time when you use variables and constants:
int age = 25; const double PI = 3.14159;
- Variable: Compiler allocates memory space (stack or heap depending on type)
- Constant: Compiler evaluates the expression and inlines the value everywhere it's used
- Memory is reserved on the stack (value types) or heap (reference types)
- The value
25is written to that memory location - The variable name
ageis a symbolic reference to that memory address
- No memory is allocated for
PI - Every occurrence of
PIin your code is replaced with3.14159directly in the IL - This is why constants are slightly faster — no memory access is needed
age = 26;— The new value is written to the same memory location- The old value (
25) is overwritten and lost
Memory Layout: Stack vs Heap
Common Confusion
const vs readonly
const — Compile‑time constant. Inlined. Only value types and string. Must be assigned at declaration.
readonly — Runtime constant. Not inlined. Can be reference types. Can be assigned in the constructor.
Remember: readonly is "set once, then never changed" — but it's not a compile‑time constant. It's evaluated at runtime.
var vs explicit type
var is statically typed — the compiler infers the type from the initialization expression. It's not a "loose" type like dynamic or JavaScript's var.
var name = "Alice"; // name is string — compiler knows this
name = 42; // Compiler error: can't assign int to string
Use var when the type is obvious from the right‑hand side. Use explicit types when the type is not obvious or when you want to be explicit for clarity.
Common Mistakes
int count;
Console.WriteLine(count); // Compiler error: unassigned local variable
Fix: Always initialize variables before reading them.
int count = 0;
Console.WriteLine(count); // Works — outputs 0
const double PI = 3.14159;
PI = 3.14; // Compiler error: cannot assign to const
Fix: Use a variable if the value needs to change, or use readonly if it's set once in a constructor.
double pi = 3.14159; // Variable — can change
pi = 3.14; // Works
const DateTime Now = DateTime.Now; // Compiler error: DateTime.Now is not a compile-time constant
Fix: Use static readonly for runtime‑evaluated values.
static readonly DateTime Now = DateTime.Now; // Works
int a = 5; // Value type — stored on stack
int b = a; // Copy of value — b is 5, a is 5
a = 10; // b is still 5 — separate copies
string s1 = "Hello"; // Reference type — stored on heap
string s2 = s1; // Both point to the same string object
s1 = "Goodbye"; // s2 still points to "Hello" — strings are immutable
Fix: Understand that value types copy data; reference types copy references.
When Should I Use It?
Use variables when:
- You need to store data that can change — user input, calculation results, counters, state flags.
- You're working with data that comes from external sources (database, API, user).
- You need to accumulate values (totals, lists, strings being built).
Use constants when:
- The value is known at compile time and will never change — mathematical constants, fixed thresholds, API keys (in secure contexts).
- You want to give a meaningful name to a "magic number" —
MAX_RETRIESinstead of3. - You need the value to be inlined for performance (though this is rarely a primary concern).
Use readonly when:
- The value is set once and never changes, but it's not known at compile time —
DateTime.Now, configuration values, dependency injections. - You're working with reference types that need to be immutable after construction.
Best practice: Prefer readonly over const when you're not certain the value is truly compile‑time constant. readonly gives you more flexibility and avoids versioning issues when constants change.
Mental Model
— You can put something in, take it out, and put something else in.
— The label (name) stays the same; the contents (value) change.
Constant = Engraved plaque
— The value is carved in stone. You can read it, but you can never change it.
— The compiler writes the value directly into your code at compile time.
readonly = Locked box with a key
— You set the value once (at construction) and then it's locked forever.
— The value is determined at runtime, not compile time.
Key Takeaway
- Variables store data that can change during your program's execution. They are the primary way your program works with dynamic data.
- Constants store fixed values that never change. They make your code more readable and maintainable by giving names to "magic numbers."
- readonly is a runtime‑constant alternative that gives you more flexibility than
const. - Value types (structs, primitives) store data directly on the stack. Reference types (classes, strings) store a reference on the stack and data on the heap.
- Always initialize variables before reading them — the compiler enforces this for local variables.
- Use
varwhen the type is obvious; use explicit types when clarity matters more. - Understanding variables and constants is the foundation for everything else in C# — data types, methods, classes, and beyond.
Check Your Understanding
You've seen how variables hold data that can change and constants hold fixed values. Let's test your understanding of when and how to use each.
1. Which of the following correctly declares a constant in C#?
Show answer
Correct: B
Why B is correct: The const keyword is used to declare a compile‑time constant. The value must be assigned at declaration and cannot change afterward.
Why A is incorrect: This declares a variable, not a constant. PI could be reassigned later.
Why C is incorrect: readonly is a runtime constant. It can be assigned in the constructor, not just at declaration. It's not a compile‑time constant like const.
Why D is incorrect: static makes a variable belong to the type rather than an instance, but it's still a variable that can change.
Reinforcement: const is for values that are truly fixed and known at compile time. Use readonly when the value is set at runtime but then never changes.
2. What will this code output?
int x = 5;
int y = x;
x = 10;
Console.WriteLine(y);
Show answer
Correct: B
Why B is correct: int is a value type. When you assign y = x, you create a copy of the value. Changing x to 10 doesn't affect y, which remains 5.
Why A is incorrect: This would be true if int were a reference type, but it's a value type. The two variables are independent.
Why C is incorrect: The code is perfectly valid and compiles successfully.
Why D is incorrect: y was initialized to the value of x (which was 5 at that time), not 0.
Reinforcement: Value types (like int, bool, double, struct) copy data when assigned. Reference types (like string, class, array) copy references. This is a crucial distinction in C#.
3. You're building a banking application. The interest rate is set by the central bank and rarely changes. The account balance changes with every deposit and withdrawal. Which approach is correct?
Show answer
Correct: B
Why B is correct: The interest rate is a fixed business rule that can be a compile‑time constant (const) if known at compile time, or readonly if loaded from configuration. The account balance must be a variable because it changes constantly.
Why A is incorrect: Account balance changes frequently — it cannot be a constant.
Why C is incorrect: Account balance cannot be a constant for the same reason. Interest rate could be either a constant or a variable, but it's better as a constant (or readonly) since it shouldn't change arbitrarily.
Why D is incorrect: readonly means the value is set once and never changes — that works for interest rate but not for account balance, which changes with every transaction.
Reinforcement: Choose const or readonly for values that are fixed. Use variables for values that change over time. Always match the storage mechanism to the data's behaviour.
4. What happens if you try to declare a constant using a value that's not known at compile time?
Show answer
Correct: C
Why C is correct: const values must be known at compile time. The compiler must be able to evaluate the expression. For example, DateTime.Now is not a compile‑time constant, so const DateTime Now = DateTime.Now; will produce a compiler error.
Why A is incorrect: This is not a warning situation — it's a hard compile‑time error.
Why B is incorrect: const can't use runtime values. This is the whole point of readonly — for runtime‑evaluated values.
Why D is incorrect: The compiler doesn't "downgrade" a constant to a variable. You'll get an error and the code won't compile.
Reinforcement: If you need a value that's determined at runtime but won't change afterward, use readonly instead of const. readonly values are set at runtime (in the constructor) and then locked.
5. Consider this code snippet. Which statement about the userName variable is true?
string userName = "Alice";
userName = "Bob";
Console.WriteLine(userName);
Show answer
Correct: C
Why C is correct: userName is a variable that holds a reference to a string. When you reassign it from "Alice" to "Bob", the variable now points to a different string object. The string "Alice" remains immutable, but the variable changed what it points to.
Why A is incorrect: You can reassign a string variable to a new string value. The string itself is immutable, but the variable can change.
Why B is incorrect: The output is "Bob" because the variable was reassigned before the WriteLine call.
Why D is incorrect: This would only happen with concatenation (e.g., userName += "Bob"), not with reassignment.
Reinforcement: "Immutable" means the object itself can't change, not that the variable can't change. This is a very common source of confusion for beginners. Strings are immutable, but string variables are still variables — they can be reassigned.
You've mastered variables and constants — the foundation of working with data in C#!