The first bug most beginners hit with variables in C# isn’t a crash. It’s a build that refuses to start, because a local variable might be read before it has a value:
decimal discount;
string guest = "Jenna Morales";
if (guest.StartsWith("J"))
discount = 0.10m;
Console.WriteLine($"{guest} gets {discount * 100}% off");
// error CS0165: Use of unassigned local variable 'discount'
Quick answer: give it a value on every path, like decimal discount = 0m;. Below, I run that fix and the rest of the variable rules on .NET 10: var, const vs readonly, fields, scope and null warnings.
Why Does C# Say “Use of Unassigned Local Variable”?
C# checks definite assignment at compile time. If any path through the code could read a local before it’s assigned, the build stops with CS0165. Here the if can be false, so discount might never get a value.

Start the variable at 0m and the same program builds and prints Jenna Morales gets 10.00% off.
The same check runs on every else branch and switch case in C#, so a variable assigned in only some cases fails the same way. Fields are different; they get defaults automatically.
How to Declare and Initialize Variables in C#
A variable declaration is a type, a name and an optional starting value. You can declare several variables of one type in a single statement, or declare first and assign later, as long as you assign before you read.
My running sample is a hotel booking in Denver for Tyler Brooks: three nights at $189.
using System.Globalization;
CultureInfo.CurrentCulture = new CultureInfo("en-US");
string guest = "Tyler Brooks"; // type, name, value
int nights = 3;
decimal rate = 189.00m;
int adults = 2, kids = 1; // two variables, one statement
string room; // declared now...
room = "Suite 412"; // ...assigned later
decimal total = nights * rate;
Console.WriteLine($"{guest}, {room}: {nights} nights x {rate:C}");
Console.WriteLine($"Total {total:C} for {adults + kids} guests");
Output:
Tyler Brooks, Suite 412: 3 nights x $189.00
Total $567.00 for 3 guests

The type decides what a variable can hold, so rate can’t take "189" as text. For the full list of built-in types and their ranges, see data types in C#. To move a value from one type to another, read type casting in C#.
Names are case-sensitive, so nights and Nights are two different variables. Locals use camelCase; the C# variable naming conventions cover the rest.
var: Implicitly Typed Local Variables
var tells the compiler to work out the type from the value on the right. The variable is still strongly typed; you just don’t write the type name. That’s also why var always needs a value on the same line.
var city = "Denver";
var nights = 3;
var total = nights * 189.00m;
Console.WriteLine(city.GetType().Name);
Console.WriteLine(nights.GetType().Name);
Console.WriteLine(total.GetType().Name);
Output:
String
Int32
Decimal
nights * 189.00m is an int times a decimal, so total became Decimal. I use var when the type is obvious from the right side, like new List<string>() from List in C#, and write the type when it isn’t.
Important: with nullable reference types on, var infers a nullable type for reference values, so var city = "Denver"; is a string? to the compiler.
Leave the value off and there’s nothing to infer from, so the build stops with CS0818:
var deposit; // no value, so no type to infer
deposit = 250.00m;
Console.WriteLine(deposit);
Build output:
C:\DotNetDemo\Variables\VarNoValue.cs(1,5): error CS0818: Implicitly-typed variables must be initialized
The build failed. Fix the build errors and run again.
const vs readonly in C#
Both stop a value from changing, but at different times. A const is baked in at compile time and must be a literal-style value. A readonly field is set once at run time, in its declaration or in a constructor.
var booking = new Booking("Carmen Diaz", new DateOnly(2026, 11, 20));
Console.WriteLine($"Max stay: {Booking.MaxNights} nights");
Console.WriteLine($"{booking.Guest} arrives {booking.Arrival:yyyy-MM-dd}");
class Booking
{
public const int MaxNights = 14; // fixed at compile time
public readonly DateOnly Arrival; // fixed per object, at run time
public readonly string Guest;
public Booking(string guest, DateOnly arrival)
{
Guest = guest; // allowed: inside the constructor
Arrival = arrival;
}
}
Output:
Max stay: 14 nights
Carmen Diaz arrives 2026-11-20
const | readonly | |
|---|---|---|
| When the value is set | Compile time | Run time (declaration or constructor) |
| Allowed types | Numbers, bool, char, string, enums | Any type |
| Can differ per object? | No, it’s implicitly static | Yes |
| Local variable? | Yes (const int x = 5;) | No, fields only |
Every booking shares MaxNights, while each one gets its own Arrival. Constants are PascalCase, as shown in the C# constant naming conventions.
Local, Instance and Static Variables
Where you declare a variable decides how long it lives and who shares it. Here two front desks check in three guests:
var lobby = new FrontDesk();
lobby.CheckIn("Jenna Morales");
lobby.CheckIn("Tyler Brooks");
var annex = new FrontDesk();
annex.CheckIn("Carmen Diaz");
Console.WriteLine($"Lobby {lobby.Count}, Annex {annex.Count}");
Console.WriteLine($"Hotel {FrontDesk.Total}");
class FrontDesk
{
public int Count; // instance field: one per desk
public static int Total; // static field: shared by every desk
public void CheckIn(string guest)
{
string message = $"Welcome, {guest}"; // local: gone after the call
Count++; Total++;
Console.WriteLine(message);
}
}
Output:
Welcome, Jenna Morales
Welcome, Tyler Brooks
Welcome, Carmen Diaz
Lobby 2, Annex 1
Hotel 3

| Kind | Declared | Lives | Default if not set |
|---|---|---|---|
| Local | Inside a method or block | Until the block ends | None, must assign (CS0165) |
| Instance field | In a class, no static | As long as its object | Type’s default |
| Static field | In a class with static | Whole app run | Type’s default |
| Parameter | In the method signature | For that call | The caller’s argument |
Parameters are variables too; functions in C# covers how they’re passed, including ref and out.
Variable Scope and Blocks
A local variable exists only inside the braces where you declare it. Each pass of a loop gets a fresh one, and code after the closing brace can’t see it.
int rooms = 3;
for (int i = 1; i <= rooms; i++)
{
int floor = i + 1; // a fresh floor on every pass
Console.WriteLine($"Room {i} is on floor {floor}");
}
// Console.WriteLine(floor); // CS0103: floor doesn't exist here
Output:
Room 1 is on floor 2
Room 2 is on floor 3
Room 3 is on floor 4
Uncomment the last line and the build fails with CS0103, because floor ended with the loop. The loop counter i follows the same rule, as the for loop in C# shows.
What Default Value Does a C# Variable Get?
Fields and properties you never assign start at their type’s default: zero for numbers, false for bool, null for reference types and the zero value for structs.
using System.Globalization;
CultureInfo.CurrentCulture = new CultureInfo("en-US");
var g = new Guest();
Console.WriteLine($"int: {g.Nights}, decimal: {g.Balance}, bool: {g.IsVip}");
Console.WriteLine($"string is null: {g.Name is null}");
Console.WriteLine($"DateOnly: {g.Arrival}");
Console.WriteLine($"default(double): {default(double)}");
class Guest
{
public int Nights { get; set; }
public decimal Balance { get; set; }
public bool IsVip { get; set; }
public string? Name { get; set; }
public DateOnly Arrival { get; set; }
}
Output:
int: 0, decimal: 0, bool: False
string is null: True
DateOnly: 1/1/0001
default(double): 0
The empty DateOnly printed 1/1/0001, the year-1 minimum. The default keyword gives you the same value anywhere, for example default(double). Struct fields work the same way; see structures in C#.
Nullable Reference Type Variables and CS8600 Warnings
New projects and file-based apps turn on nullable reference types. A plain string then promises it’s never null, and string? says null is allowed. Break that promise and you get a warning, not an error.
string? middle = MiddleName("Tyler Brooks"); // ? = null is allowed
string shown = middle; // warning CS8600
Console.WriteLine($"Middle name: {shown ?? "(none)"}");
Console.WriteLine($"Length: {middle?.Length ?? 0}");
static string? MiddleName(string fullName)
{
string[] parts = fullName.Split(' ');
return parts.Length == 3 ? parts[1] : null;
}
Build and run output:
C:\DotNetDemo\Variables\NullableWarnings.cs(2,16): warning CS8600: Converting null literal or possible null value to non-nullable type.
Middle name: (none)
Length: 0

The ?. and ?? operators read a maybe-null variable safely. For other ways to test for null, see how to check for null values in C#.
Printing Variables with String Interpolation (and Swapping Two)
Put a $ before a string and any variable inside braces is printed in place. A colon adds a format, and a comma pads to a width. A tuple swaps two variables without a temp variable.
using System.Globalization;
CultureInfo.CurrentCulture = new CultureInfo("en-US");
string first = "Jenna", last = "Morales";
decimal balance = 1249.5m;
Console.WriteLine($"Guest: {last}, {first}");
Console.WriteLine($"Balance: {balance:C} |{balance,10:N2}|");
int checkIn = 18, checkOut = 15; // typed backwards
(checkIn, checkOut) = (checkOut, checkIn); // swap with a tuple
Console.WriteLine($"Stay: Nov {checkIn} to Nov {checkOut}");
Output:
Guest: Morales, Jenna
Balance: $1,249.50 | 1,249.50|
Stay: Nov 15 to Nov 18
The {balance,10:N2} part right-aligned 1,249.50 in ten characters, and the tuple fixed the backwards dates. The classic temp-variable and arithmetic ways are in swap two numbers in C#.
Common Variable Errors in C# and How to Fix Them
I broke the hotel code on purpose to collect the errors I see most in beginner code reviews:
const int MaxNights = 14;
MaxNights = 21; // change a constant
var room = new Room();
room.Number = 412; // set readonly outside the constructor
for (int i = 0; i < 2; i++) { int floor = i; }
Console.WriteLine(floor); // use a variable outside its block
class Room { public readonly int Number = 101; }
Build output:
C:\DotNetDemo\Variables\Errors.cs(2,1): error CS0131: The left-hand side of an assignment must be a variable, property or indexer
C:\DotNetDemo\Variables\Errors.cs(5,1): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer)
C:\DotNetDemo\Variables\Errors.cs(8,19): error CS0103: The name 'floor' does not exist in the current context
The build failed. Fix the build errors and run again.

| Error | Cause | Fix |
|---|---|---|
| CS0165 | Local read before it’s assigned | Assign on every path, or at declaration |
| CS0131 | Assigning to a const | Use a normal variable or readonly field |
| CS0818 | var with no value | Initialize it, or write the type |
| CS0191 | Setting a readonly field outside the constructor | Set it in the constructor or an init property |
| CS0103 | Using a variable outside its block | Declare it in the outer scope |
Errors like these stop the build. Values that go wrong while the app runs need try catch in C# instead.
Which Kind of Variable Should You Use?
- A local for anything one method needs, declared close to where you use it.
varwhen the type is plain from the right side; the type name when it isn’t.constfor values that never change, like a tax rate in the law;readonlyfor values fixed per object.- An instance field for an object’s own data, a static field only for data every object shares.
string?(andint?) when “no value” is a real answer.
These go further on the topics around variables:
- Check the full set of naming rules in C#
- Learn more about tuples beyond swapping
- See what C# 14 changed, including the field keyword
- Set up VS Code to run these examples
Frequently Asked Questions
What is a variable in C#?
A variable is a named storage location with a fixed type. You declare it with a type and a name, like int nights = 3;, and the compiler only lets it hold values of that type.
Does var make C# dynamically typed?
No. var only asks the compiler to infer the type from the initializer. The variable keeps that type for its whole life, so var nights = 3; is an int and can’t later hold a string.
What is the difference between const and readonly in C#?
A const is a compile-time value that’s the same everywhere and is implicitly static. A readonly field is set once at run time, in its declaration or a constructor, so each object can have its own value.
Do C# local variables have default values?
No. A local must be assigned before it’s read, or the build fails with CS0165. Fields, array elements and static variables do get default values, such as 0, false or null.
How do I fix “Use of unassigned local variable” in C#?
Give the variable a value when you declare it, or make sure every if/else path and every switch case assigns it before the first read. Microsoft’s rules are in Declaration statements on Microsoft Learn.
Bijay Kumar is a renowned software engineer, accomplished author, and distinguished Microsoft Most Valuable Professional (MVP) specializing in SharePoint. With a rich professional background spanning over 15 years, Bijay has established himself as an authority in the field of information technology. He possesses unparalleled expertise in multiple programming languages and technologies such as ASP.NET, ASP.NET MVC, C#.NET, and SharePoint, which has enabled him to develop innovative and cutting-edge solutions for clients across the globe. Read more…