C# Variables

A variable is a named place where a C# program stores a value while it runs. Variables let you remember data, update it, calculate with it, and pass it to other parts of your program. C# variables are strongly typed, which means each variable has a specific type such as int, string, bool, or decimal, and the compiler checks that you use the value correctly.

Overview: How C# Variables Work

A variable declaration tells the compiler three important things: the variable’s type, its name, and optionally its initial value. For example, int score = 90; declares a local variable named score that stores a whole number. After declaration, code in the same scope can read the variable, assign a new compatible value to it, or use it inside expressions.

C# is statically typed. The type of a local variable is known at compile time, before the program runs. This gives the compiler enough information to catch many errors early. If you declare int age = 16;, C# will allow arithmetic such as age + 1. It will not allow age = "sixteen"; because a string is not an integer. This type checking is one reason C# programs can be refactored and maintained safely in large applications.

Variables are not all stored the same way internally. Local variables that hold simple value types, such as int, double, bool, and decimal, directly contain their value. Local variables that hold reference types, such as string or most class objects, hold a reference to an object managed by the runtime. A string variable does not contain every character inline in the local variable slot; it refers to a string object. The CLR manages object memory and can reclaim objects that are no longer reachable.

Assignment changes what a variable currently holds. With value types, assignment copies the value. With reference types, assignment copies the reference, so two variables can refer to the same object. Strings are reference types, but they are immutable, meaning string operations create new strings instead of changing the existing string object. You will see reference sharing more clearly when you work with arrays, lists, and classes later.

Variables also have scope and lifetime. Scope is the region of code where a variable name can be used. A local variable declared inside Main can be used after its declaration until the end of the surrounding block. A variable declared inside an if block or loop block normally cannot be used outside that block. Lifetime is how long the storage exists at runtime; local variables exist while their method call is active, while objects they reference may live longer if something else still references them.

Syntax

type variableName = initialValue;
variableName = newValue;
var inferredName = initialValue;
const type ConstantName = constantValue;
Part Meaning
type The kind of value the variable can hold, such as int, string, bool, or decimal.
variableName The identifier used to read or assign the variable later. Local variables usually use camelCase.
initialValue The first value assigned to the variable. Local variables must be definitely assigned before they are read.
var Asks the compiler to infer the variable’s type from the initial value. The type is still fixed after that.
const Declares a compile-time constant. Its value must be known when the program is compiled and cannot be changed.

These declarations compile as ordinary statements:

int count = 0;
string course = "C#";
var nextCount = count + 1;
const double PassingScore = 70.0;

Examples

Declaring and Updating Variables

using System;

class Program
{
    static void Main()
    {
        string studentName = "Ava";
        int points = 10;
        bool isEnrolled = true;

        points = points + 5;

        Console.WriteLine($"Student: {studentName}");
        Console.WriteLine($"Points: {points}");
        Console.WriteLine($"Enrolled: {isEnrolled}");
    }
}

Output:

Student: Ava
Points: 15
Enrolled: True

The variables begin with initial values. The statement points = points + 5; reads the old value of points, adds five, and assigns the result back to the same variable. The bool value prints as True because that is the standard text form used by .NET.

Using Variables in Expressions

using System;

class Program
{
    static void Main()
    {
        int apples = 6;
        int oranges = 4;
        int totalFruit = apples + oranges;
        double averagePerBasket = totalFruit / 2.0;

        Console.WriteLine($"Apples: {apples}");
        Console.WriteLine($"Oranges: {oranges}");
        Console.WriteLine($"Total fruit: {totalFruit}");
        Console.WriteLine($"Average per basket: {averagePerBasket}");
    }
}

Output:

Apples: 6
Oranges: 4
Total fruit: 10
Average per basket: 5

Variables can be combined in expressions. totalFruit stores the result of adding two int variables. The expression totalFruit / 2.0 uses 2.0, a double literal, so the division is floating-point division instead of integer division. That matters when the result is not a whole number.

A Realistic Receipt Calculation

using System;
using System.Globalization;

class Program
{
    static void Main()
    {
        const decimal TaxRate = 0.0825m;
        string item = "Desk lamp";
        int quantity = 3;
        decimal unitPrice = 19.99m;

        decimal subtotal = quantity * unitPrice;
        decimal tax = subtotal * TaxRate;
        decimal total = subtotal + tax;

        Console.WriteLine($"Item: {item}");
        Console.WriteLine($"Quantity: {quantity}");
        Console.WriteLine($"Subtotal: {subtotal.ToString("F2", CultureInfo.InvariantCulture)}");
        Console.WriteLine($"Tax: {tax.ToString("F2", CultureInfo.InvariantCulture)}");
        Console.WriteLine($"Total: {total.ToString("F2", CultureInfo.InvariantCulture)}");
    }
}

Output:

Item: Desk lamp
Quantity: 3
Subtotal: 59.97
Tax: 4.95
Total: 64.92

This example uses several variable types together. decimal is a good choice for base-10 money calculations because it avoids many binary floating-point surprises. TaxRate is a constant because the program should not accidentally assign a new tax rate later in the method.

How Variables Work Step by Step

  1. The compiler reads a declaration such as int points = 10; and records that points is an int local variable in the current block.
  2. The initializer 10 is checked against the variable type. Because 10 is a valid int literal, the declaration is accepted.
  3. When the compiler sees points = points + 5;, it checks that points has already been assigned, that + is valid for integers, and that the result can be stored back into an int.
  4. The compiler emits intermediate language instructions that reserve local slots, load values, perform operations, and store results.
  5. At runtime, the CLR executes those instructions. Local values are stored in method-local storage managed by the runtime, and reference-type objects are tracked by the garbage collector.

C# also has definite assignment rules. A local variable does not automatically become usable just because you declared it. If the compiler cannot prove that a local variable has received a value before it is read, compilation fails. This prevents unpredictable reads of uninitialized local data.

Common Mistakes

Reading a Local Variable Before Assignment

int score;
Console.WriteLine(score);

This does not compile. The variable exists, but no value has been assigned before it is read. Assign a value first, even if that value is only a sensible default.

int score = 0;
Console.WriteLine(score);

Output:

0

Assuming var Means Dynamic

var level = 3;
level = "advanced";

This does not compile. var does not create a variable whose type can change. It tells the compiler to infer the type once. Here, level is inferred as int, so a string cannot be assigned later.

var level = 3;
level = 4;
Console.WriteLine(level);

Output:

4

Losing Precision With Integer Division

using System;

class Program
{
    static void Main()
    {
        int completed = 3;
        int total = 4;
        double ratio = completed / total;
        double correctedRatio = completed / (double)total;

        Console.WriteLine(ratio);
        Console.WriteLine(correctedRatio);
    }
}

Output:

0
0.75

The first division uses two int values, so C# performs integer division and discards the fraction before assigning the result to double. Cast one operand or use a floating-point literal when fractional results matter.

Best Practices

  • Use clear camelCase names for local variables, such as studentName, totalPrice, and isActive.
  • Initialize local variables close to where you first use them.
  • Prefer explicit types when the type teaches the reader something important, such as decimal unitPrice.
  • Use var when the type is obvious from the right side, such as var message = "Saved";.
  • Use const for true compile-time constants that should never change.
  • Choose numeric types intentionally: int for whole counts, double for scientific-style measurements, and decimal for money-like decimal values.
  • Keep variable scope as small as practical so names do not leak into unrelated code.
  • Do not reuse one variable for unrelated meanings; create a new well-named variable instead.

Practice Exercises

  1. Create variables for a book title, page count, and whether you have finished it. Print all three values with labels.
  2. Write a program that stores a test score and maximum score, calculates the percentage as a double, and prints it.
  3. Create a receipt program with const decimal TaxRate, an item name, quantity, and unit price. Print the subtotal, tax, and total.

Summary

  • A C# variable is a named storage location with a fixed compile-time type.
  • Declarations can include an initial value, and local variables must be assigned before they are read.
  • Assignment replaces the variable’s current value or reference with a new compatible one.
  • var uses type inference, but the inferred type is still static and cannot change later.
  • const creates a value that is known at compile time and cannot be reassigned.
  • Scope controls where a variable name can be used, and smaller scopes usually make code easier to understand.