Back to Blog
C#

C# Variable Initialization: Rules and Defaults

c# variable initialization: Learn how C# handles variable initialization: default values, definite assignment, var inference, and common pitfalls.

C#variable initializationdefault valuesdefinite assignmentvar keywordout parameters
Illustration of C# variable initialization showing default values and assignment rules.

C# variable initialization is governed by definite assignment rules enforced at compile time. A local variable must be definitely assigned before its value is read, or the compiler reports an error. This differs from fields, which receive a default value automatically. Understanding these rules is essential for writing predictable code.

Default Values for Fields and Array Elements

Fields declared in a class or struct are automatically initialized to their default value when the containing object is constructed. The default value is the result of default(T) for the field's type: zero for numeric types, false for bool, and null for reference types.

class Example { private int _number; // default 0 private string _text; // default null private bool _flag; // default false }

Array elements follow the same rule. When you create an array with new int[5], each element is initialized to 0. For a reference type array, each element is null until you assign it.

Local variables do not get a default value. The compiler requires that every local variable be explicitly assigned before it is used. This is a deliberate design decision: it prevents reading memory that may contain stale data.

int count; Console.WriteLine(count); // CS0165: Use of unassigned local variable 'count'

Declaring and Initializing in One Step

The most straightforward form of C# variable initialization is to declare and assign in a single statement. This satisfies the compiler's definite assignment rule and makes the initial state explicit.

int count = 10; string name = "Ada"; var status = "active";

The var keyword does not introduce dynamic typing. It instructs the compiler to infer the variable's type from the initializer expression. status is a string, and count is an int. Using var is a readability choice, not a performance decision.

The default Literal and default(T)

C# has a default literal that produces the default value of a type. It was introduced in C# 7.1 and is especially useful in generic code where the type is not known at compile time.

int number = default; // 0 string text = default; // null bool flag = default; // false

Before C# 7.1, you had to write default(T) explicitly. The literal form is equivalent and works in any context where the target type is known. For nullable value types, default is null:

int? maybeNumber = default; // null

In generic methods, default(T) is the only way to obtain a default value when T is unconstrained:

public T GetDefault<T>() { return default(T); }

Initializing out and ref Arguments

Method parameters with the out modifier do not require the caller to initialize the variable before the call. The method must assign a value to the parameter before returning. This is a common pattern for methods that return multiple results.

bool TryParse(string input, out int result) { if (int.TryParse(input, out result)) { return true; } result = 0; return false; }

In contrast, a ref parameter must be initialized before the call because the method may read it without writing first. The compiler enforces this distinction.

int value = 5; Modify(ref value);

Common Compiler Errors and Their Causes

The most frequent initialization-related error is CS0165, "Use of unassigned local variable." It occurs when you attempt to read a local variable that the compiler cannot prove has been assigned. This often happens in conditional branches:

int result; if (condition) { result = 1; } Console.WriteLine(result); // CS0165: use of unassigned local variable

The compiler does not track runtime conditions; it requires that every possible execution path assigns the variable before use. The fix is to initialize the variable at declaration or to provide an else branch.

Another related error is CS0170, "Use of possibly unassigned field," which can appear when you access a struct field that has not been assigned in all constructors. Struct constructors must assign every field before returning.

Choosing Between Explicit Types and var

var is not a replacement for explicit types; it is a tool for reducing visual clutter when the type is obvious from the initializer. For example, var dictionary = new Dictionary<string, List<int>>(); is clearer than repeating the full type name.

However, using var with a method call can obscure the actual type if the method's return type is not obvious. In that case, an explicit type improves readability and prevents accidental type mismatches. The choice is about maintainability, not runtime behavior.

Object Initializers and Collection Initializers

Object initializers let you set property values at construction time without writing multiple assignment statements. They are syntactic sugar that the compiler converts into property assignments after the constructor runs.

var person = new Person { Name = "Ada", Age = 36 };

This is equivalent to:

var person = new Person(); person.Name = "Ada"; person.Age = 36;

Object initializers are useful when you want to create an object in a fully initialized state. They do not change the underlying initialization rules; the constructor still runs first.

Runtime and Allocation Considerations

For value types, initialization is a copy operation. Assigning int x = 10; stores the value directly in the stack slot or field memory. There is no heap allocation. For reference types, new allocates an object on the heap and assigns the reference to the variable. Default values are set by the runtime as part of object construction or array allocation, which is why uninitialized fields are safe to read.

The default literal and default(T) produce the same result as the runtime's automatic initialization. They are useful when you need to explicitly reset a variable or when writing generic code that must handle any type. These operations have no measurable performance cost beyond the assignment itself.

c# variable initialization: Practical Usage and Code Example | RYUSLOG DEV