.NET
foreach loop
NullReferenceException
C# programming
error handling

Why does .NET foreach loop throw NullRefException when collection is null?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

foreach in C# does not treat null as an empty collection. If the collection reference is null, the runtime throws NullReferenceException because the loop still needs an enumerator object and there is nothing to call it on. The confusion comes from foreach looking like a language primitive when it is really syntax that compiles down to method calls on the collection.

What foreach Expands To

Given this code:

csharp
1foreach (var item in items)
2{
3    Console.WriteLine(item);
4}

the compiler turns it into logic similar to this:

csharp
1using System;
2using System.Collections.Generic;
3
4IEnumerable<int>? items = new List<int> { 1, 2, 3 };
5
6using var enumerator = items.GetEnumerator();
7while (enumerator.MoveNext())
8{
9    var item = enumerator.Current;
10    Console.WriteLine(item);
11}

If items is null, the call to items.GetEnumerator() dereferences a null reference, so the loop fails before the first iteration.

That is why foreach on null behaves differently from foreach on an empty list. An empty list still has a valid enumerator. A null reference does not.

Guard the Collection Explicitly

The simplest fix is a null guard:

csharp
1if (items != null)
2{
3    foreach (var item in items)
4    {
5        Console.WriteLine(item);
6    }
7}

This is good when null means "there is no collection" and you want that meaning to stay visible in the code.

If you want to treat null as empty, coalesce to an empty sequence:

csharp
1using System;
2using System.Collections.Generic;
3using System.Linq;
4
5IEnumerable<int>? items = null;
6
7foreach (var item in items ?? Enumerable.Empty<int>())
8{
9    Console.WriteLine(item);
10}

That keeps the loop body simple and removes the exception.

Prefer Non-Null Collections by Design

The best fix is often not a guard at the loop site. It is making sure collections are initialized and stay non-null throughout the object lifetime.

csharp
1using System.Collections.Generic;
2
3public class OrderBatch
4{
5    public List<string> OrderIds { get; } = new();
6}

Now callers can safely iterate:

csharp
1var batch = new OrderBatch();
2
3foreach (var orderId in batch.OrderIds)
4{
5    System.Console.WriteLine(orderId);
6}

Returning empty collections instead of null is usually the more ergonomic API design because callers do not need to special-case the absence of items.

Nullable Reference Types Make the Risk Obvious

With nullable reference types enabled, the compiler can help highlight risky loops:

csharp
1#nullable enable
2
3using System.Collections.Generic;
4
5IEnumerable<string>? names = null;

Iterating directly over names should prompt a warning because it may be null. That warning is useful. Do not silence it blindly. Decide whether the collection should be nullable at all.

If null is a valid state, handle it explicitly. If it is not, redesign the API so the property or return value is always initialized.

Use the Right Semantics for Your Domain

There is a meaningful difference between:

  • no collection object was provided
  • a collection was provided but it contains zero items

Some domains care about that distinction. For example, a partial update payload may use null to mean "do not touch this field" and an empty list to mean "clear it." In that case, replacing null with empty too early could lose information.

So the practical rule is:

  • return empty collections when the caller only needs iteration
  • keep null only when it conveys business meaning

Common Pitfalls

  • Assuming foreach treats null the same way it treats an empty list.
  • Adding null coalescing everywhere instead of fixing an API that should never return null collections.
  • Ignoring the semantic difference between null and empty in request models.
  • Disabling nullable warnings instead of deciding on a clear collection contract.
  • Catching NullReferenceException after the fact instead of preventing the null dereference.

Summary

  • 'foreach throws on null because it must call GetEnumerator() on the collection reference.'
  • An empty collection is safe because it still provides a valid enumerator.
  • Use null guards or Enumerable.Empty<T>() when null should behave like empty.
  • Prefer API designs that initialize collections instead of returning null.
  • Keep null collections only when null carries real domain meaning.

Course illustration
Course illustration

All Rights Reserved.