Back to Blog
C#

C# Variable Declaration vs Initialization

c# variable declaration vs initialization: Understand the difference between declaring and initializing variables in C#, including default values, nullability, var inf...

C#variable declarationvariable initializationnullabilityvar keyworddefault values
Diagram showing a variable being declared and then initialized with a value, highlighting the two-step process in C#.

c# variable declaration vs initialization requires a clear understanding of the core syntax, runtime behavior, and practical implementation patterns demonstrated in the examples below.

In C#, declaration and initialization are two distinct operations that are often combined on a single line. The difference matters because an uninitialized variable has a default value, and in some cases the compiler will not allow you to read it before assignment. Consider the following:

int number; // declaration only number = 42; // initialization (assignment) int other = 42; // declaration and initialization together

This article focuses on c# variable declaration vs initialization and the practical consequences of each choice in everyday code.

Declaration vs Initialization: The Core Distinction

Declaration introduces a variable and its type into scope. Initialization assigns a value to that variable for the first time. In C#, a variable that is declared but not initialized has a default value, but that default is not always safe to use. For value types, the default is the zero value of that type. For reference types, the default is null.

int i; // default is 0 bool flag; // default is false double d; // default is 0.0 string s; // default is null object obj; // default is null

The compiler enforces definite assignment. You cannot read a local variable before it has been assigned, even though it has a default value. This rule prevents the accidental use of uninitialized state.

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

Fields and properties, on the other hand, are automatically initialized to their default values when an object is constructed. The distinction between local variables and fields is a common source of confusion.

What the Compiler Does With an Uninitialized Variable

The compiler tracks whether a local variable has been definitely assigned. If a variable is declared but never assigned, and you attempt to read it, the compiler emits error CS0165. This is a compile-time check, not a runtime behavior. The variable may still have a default value in memory, but the compiler prevents you from relying on it.

For fields, the runtime initializes them to the default value before the constructor runs. For example:

class Example { private int _count; // initialized to 0 automatically private string _name; // initialized to null automatically }

This difference is important when you design types. A field that is never explicitly initialized is not a bug, but a local variable that is read before assignment is a compile error.

var vs Explicit Type: When Initialization Matters

The var keyword infers the type from the initializer. This means var requires an initialization expression. You cannot declare a variable with var and assign it later without an initial value.

var value = 10; // inferred as int var text = "hello"; // inferred as string

The following does not compile:

var number; // CS0818: Implicitly-typed variables must be initialized

Using var forces you to initialize at declaration. This can be a good thing because it avoids the unassigned local variable issue. However, it also means you cannot declare a variable and conditionally assign it in separate branches without a fallback value.

Explicit typing gives you more flexibility:

int result; if (condition) { result = 1; } else { result = 2; } Console.WriteLine(result); // valid

The compiler's definite assignment analysis understands this pattern. With var, you would need to assign a default value first, which may not be semantically meaningful.

Nullable Reference Types and Initialization Requirements

Starting with C# 8, nullable reference types are enabled by default in new project templates. This feature changes how the compiler treats reference type declarations. A non-nullable reference type must be initialized with a non-null value, or the compiler warns you.

string name; // warning CS8618: Non-nullable field 'name' must contain a non-null value when exiting constructor

For local variables, the compiler uses flow analysis to determine whether a variable is null before it is used. Consider:

string? maybeNull = GetValue(); if (maybeNull != null) { Console.WriteLine(maybeNull.Length); // safe }

When you declare a non-nullable reference type, you are making a contract that the variable will never be null. The compiler helps enforce that contract by warning when you assign a possibly null value or when you fail to initialize.

This has a direct impact on c# variable declaration vs initialization. A non-nullable reference type that is only declared and not initialized will produce a warning, and the variable may be used in a way that causes a runtime NullReferenceException if you suppress the warning.

Initializing Fields, Properties, and Constructor Parameters

Fields and properties have their own initialization rules. A field can be initialized at declaration, in the constructor, or in a property initializer. The order of initialization matters.

class Order { private List<Item> _items = new List<Item>(); // field initializer private decimal _total; public Order(decimal total) { _total = total; // constructor assignment } }

Property initializers run before the constructor body. If you have both a field initializer and a constructor assignment, the constructor assignment wins.

For read-only fields, you must initialize them either at declaration or in the constructor. You cannot assign them later.

class Config { private readonly int _port; public Config(int port) { _port = port; // required } }

Object initializers provide a way to set public properties at construction time without writing a constructor for every combination:

var person = new Person { FirstName = "Ada", LastName = "Lovelace" };

This is a form of initialization that happens after the constructor runs. It is useful for immutable objects that expose settable properties.

Performance and Memory Behavior of Uninitialized Variables

From a runtime perspective, an uninitialized local variable does not have a meaningful performance cost. The stack space is reserved when the method is entered, and the default value is already present in memory. The compiler's definite assignment check is purely static and has no runtime overhead.

For fields, the runtime zeroes memory when an object is allocated. This is a built-in behavior of the CLR. Explicitly initializing a field to its default value, such as int _count = 0;, is redundant and does not change performance.

A more relevant performance consideration is the choice between var and explicit types. var does not affect runtime behavior; it is a compile-time feature. The generated IL is identical. The only performance impact is on compile time, which is negligible.

The real cost comes from initializing large objects or collections. For example, initializing an array with default values is cheap because the runtime fills it with zeros. But initializing a list with many elements requires allocation and copying. That cost is inherent to the data structure, not to the declaration style.

Common Mistakes and How to Avoid Them

One common mistake is assuming that a local variable has a default value that you can safely read. The compiler prevents this, but the error message can be confusing if you are used to other languages.

Another mistake is using var when the initializer does not clearly convey the type, especially with null:

var value = null; // error CS0815: Cannot assign <null> to an implicitly-typed variable

To fix this, you must specify the type explicitly:

string? value = null;

With nullable reference types, a related mistake is declaring a non-nullable variable and assigning a nullable expression. The compiler warns, and you may end up with a null value at runtime if you ignore the warning.

A third mistake is over-initializing fields to their default values. This adds noise without changing behavior. Prefer to rely on the runtime's automatic zero-initialization for fields.

When you need to declare a variable without an immediate value, use explicit typing and ensure the variable is assigned before any read. The compiler will help you verify this.

For example, consider a method that returns a result based on a condition:

public string GetStatus(bool isReady) { string status; if (isReady) { status = "ready"; } else { status = "not ready"; } return status; }

This compiles without warnings because the compiler sees that status is definitely assigned on all paths. If you used var, you would need to assign an initial value, which might not be meaningful.

The choice between declaration and initialization is not just a stylistic preference. It affects compile-time safety, nullability analysis, and the clarity of your intent. Prefer initializing at declaration when the value is known. Use declaration-only when the value must be computed conditionally, and rely on the compiler's definite assignment rules to keep your code safe.