Code Housekeeping - Part 14 - Don't Return NULL Collections
[C#, Languages, CodeHouseKeeping, Code, Quality]
Code Housekeeping refers to general rules of thumb that make code easier to read, digest, and modify for other developers, yourself included.
In today’s post, we will look at a common problem with collections.
Let us take our usual example, a domain model with the following types - a Spy, defined thus:
public sealed class Spy
{
public required string FirstName { get; init; }
public required string Surname { get; init; }
public required DateOnly DateOfBirth { get; init; }
}
And an Agency, defined thus:
public sealed class Agency
{
public required string Name { get; init; }
public required Spy[] Spies { get; init; }
}
Suppose we want to create a new Agency that does not presently have any Spy.
One way would be to do it this way:
var agency = new Agency()
{
Name = "Savak",
Spies = null
};
This works, but it is a problem waiting for you downstream.
Suppose later in the program we wrote this code:
//
// Later
//
// List all the spies in this agency
foreach (var spy in agency.Spies)
{
Console.WriteLine($"{spy.FirstName} {spy.Surname}");
}
Running this program will throw a NullReferenceException.
Unhandled exception. System.NullReferenceException: Object reference not set to an instance of an object.
at Program.<Main>$(String[] args) in /Users/rad/Projects/BlogCode/EmptyCollections/Program.cs:line 12
The solution to this is to initialize the Spies collection to an empty collection.
This can be done in several ways:
var agency2 = new Agency()
{
Name = "Savak",
Spies = Array.Empty<Spy>()
};
A better way to do this is as follows:
var agency2 = new Agency()
{
Name = "Savak",
Spies = []
};
This is using the collection expression syntax, which, besides being terse, means that if you change the collection type to something else, like a list, your initialization code does not need to change.
If you are using a traditional class without the required and init modifiers, define it like this:
public sealed class Agency
{
public string Name { get; set; }
public Spy[] Spies { get; set; } = [];
}
This way, if the user forgets to initialize the collection, it is always a safe empty collection.
TLDR
Do not return NULL in the place of empty collections.
The code is in my GitHub.
Happy hacking!