Author avatar

Christian Findlay

Using the Conditional and Null-coalescing Operators

Christian Findlay

  • Nov 9, 2019
  • 4 Min read
  • 11 Views
  • Nov 9, 2019
  • 4 Min read
  • 11 Views
Languages Frameworks and Tools
C#

Introduction

Null checking is an essential part of developing quality C# code. If code attempts to access a member of a null object reference, it throws a NullReferenceException. However, using if statements to check for null references can make the code more verbose.

The null-coalescing and null-conditional operators can reduce the amount of code that needs to be written to avoid a NullReferenceException. This article explains how to use these operators.

Null Checking

Consider this code. It throws a NullReferenceException.

1
2
3
4
5
6
7
8
9
10
11
12
13
internal class Program
{
    private static void Main(string[] args)
    {
        Item item = null;
        Console.WriteLine($"Name: {item.Name}");
    }
}

internal class Item
{
    public string Name { get; }
}
cs

To fix this code, we could add an if statement to check for null.

1
2
3
4
5
6
7
8
9
10
11
12
13
private static void Main(string[] args)
{
    Item item = null;

    if (item != null)
    {
        Console.WriteLine($"Name: {item.Name}");
    }
    else
    {
        Console.WriteLine($"Name: ");
    }
}
cs

However, the above code increases the complexity and creates another code path.

Null-conditional Operator

Another way to solve this issue is to use a null-conditional operator, ?.

1
2
3
4
5
private static void Main(string[] args)
{
    Item item = null;
    Console.WriteLine($"Name: {item?.Name}");
}
cs

The part to the right of the ? only evaluates if the part to the left is not null. Otherwise, the code returns null. So, in the case above, item?.Name evaluates to null, but it does not throw an exception because there is no attempt to access a member on a null reference. Use the null-conditional operator on members of namespaces, types, array elements, access methods, or to invoke delegates.

The class below has two methods that raise an event. The dangerous version throws a NullReferenceException if there is no event handler attached. The safe version does not. It is always safe to call the method, even when there is no event handler attached.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class LongProcess
{
    public event EventHandler<string> Finished;

    public void FinishSafely()
    {
        Finished?.Invoke(this, "The process finished successfully");
    }

    public void FinishDangerously()
    {
        Finished.Invoke(this, "The process finished successfully");
    }
}
cs

Null-coalescing Operator

?? is the null-coalescing operator. It returns the value of the part on the left if it is not a null reference. Otherwise, it returns the value of the part on the right. Use this operator to fall back on a given value.

In cases where a statement could return null, the null-coalescing operator can be used to ensure a reasonable value gets returned. This code returns the name of an item or the default name if the item is null. As you can see, this operator is a handy tool when working with the null-conditional operator.

1
2
3
4
5
6
7
private static void Main(string[] args)
{
    var defaultName = "Default";
    Item item = null;
    Console.WriteLine($"Name: {item?.Name ?? defaultName}");
    Console.ReadLine();
}
cs

Output:

Default

From C# 7 onwards, it has been possible to use the null-coalescing operator to shorten the validation of arguments. This class requires the message argument in the constructor. Before C# 7, validation would require an if statement.

1
2
3
4
5
6
7
8
9
10
internal class MessageProcessor
{
    private readonly string _Message;

    public MessageProcessor(string message)
    {
        if (message == null) throw new ArgumentNullException(nameof(message));
        _Message = message;
    }
}
cs

Using the null coalescing operator allows this to be shortened to the code below.

1
2
3
4
5
6
7
8
9
internal class MessageProcessor
{
    private readonly string _Message;

    public MessageProcessor(string message)
    {
        _Message = message ?? throw new ArgumentNullException(nameof(message));
    }
}
cs

Conclusion

Null checking is important for code stability. The null-conditional operator can be used to simplify null checking. The null-coalescing operator is a great complement to it and can further simplify code where the aim is to return something other than null.

0