Avoiding null: The Case for Returning Empty Lists or Arrays in C#

Sheldon Cohen
3 min readJun 1, 2023

Why You Should Return an Empty Array or List in C# Instead of Null

Programmers around the world have all experienced the dread that comes with encountering a NullReferenceException. These errors can occur when you’re working with complex applications, and if not handled properly, can result in serious headaches and hours of debugging. In C#, developers face the dilemma of whether to return null or an empty list or array when a method is not able to return values. Often times, returning an empty list or array is often a better choice than returning null.

The Problem with Null

The main issue with null is that it can lead to the infamous NullReferenceException. The exception arises because there’s nothing there to call upon — it’s like trying to open a door in a house that doesn’t exist!

Example:


List<string> myList = GetList("Susan");
// throws NullReferenceException if GetList returns null
int count = myList.Count;

public static List<string>? GetList(string filter)
{
List<string> strings = new List<string> { "Jane", "Bob" };
List<string> result = strings.Where(s => s.Contains(filter)).ToList();

return result.Count > 0 ? result : null;
}

The Solution: Empty Collections

To avoid the potential pitfalls of returning null, it’s often preferable to return an empty list or array. When the client code receives an empty list or array, it can operate on it just like it would with a populated list or array, without the fear of a NullReferenceException. This makes it easier to write safe, robust code. It also makes the intent of your code clearer and eliminates the need for the client code to check for null before using the returned value.

Consider the following code:


List<string> myList = GetList("mike");
// safe, even if GetList returns an empty list
int count = myList.Count;

public static List<string>? GetList(string filter)
{
List<string> strings = new List<string> { "Jane", "Bob" };
List<string> result = strings.Where(s => s.Contains(filter)).ToList();

return result.Count > 0 ? result : Enumerable.Empty<string>().ToList();
}

With this approach, GetList can return an empty list when there are no strings to return, and the client code can safely call the Count property without needing to check for null.

Beside not having to do a null check, by using an Empty Collection, you simplify the conditional checks, and simplify your code’s flow. Like in the below example, you don’t need a lot of conditional checking in your code, slimming it down and making it easier to read.

// Simplified flow:
List<string> myList = GetList("Alice");
foreach (var item in myList)
{
Console.WriteLine(item); // Works even if the list is empty
}

Am I going to Incur a Cost using an Empty Collection?

One of the arguments against returning an empty list or array is that creating an empty collection can have a cost in terms of memory and performance. However, in many cases, this cost is minimal. Moreover, C# offers a way to return an empty list or array without creating a new one each time.

The Array.Empty<T> method returns a singleton instance of an empty array. This method doesn’t allocate memory for an empty array; instead, it always returns the same array instance. This way, you can return an empty array without worrying about the performance implications.


public int[] GetNumbers()
{
// Some logic here…
if (/* no numbers to return */) return Array.Empty<int>();
}

Similarly, for a list, you can return Enumerable.Empty<T>().ToList(), which also doesn’t allocate memory for an empty list.

Wrapping it up

Returning empty lists or arrays instead of null can help you write code that’s safer and easier to understand. It eliminates the risk of NullReferenceException when the returned value is used and makes it clear that the method didn’t find anything to return. The potential performance cost of creating empty collections can be avoided by returning singleton instances of empty arrays or lists.

This approach can save you a lot of time and frustration in the long run. No more unnecessary null checks or unexpected NullReferenceException! Instead, you get clear, robust code that behaves consistently, whether it’s working with a full list, an empty one, or anything in between.

Sign up to discover human stories that deepen your understanding of the world.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

Sheldon Cohen
Sheldon Cohen

Written by Sheldon Cohen

Technology professional with 15+ years of software development

Responses (1)

Write a response

Is it just me, but there are no difference in the code examples?

Recommended from Medium

Lists

See more recommendations