Author avatar

Dániel Szabó

Null Propagation Operator in C#

Dániel Szabó

  • Jan 28, 2020
  • 5 Min read
  • 238 Views
  • Jan 28, 2020
  • 5 Min read
  • 238 Views
Languages Frameworks and Tools
C#

Introduction

Back in 2016, Microsoft held an event called Visual Studio Connect() where they released the preview version of Visual Studio 2015, and C# 6.0. This new version incorporated many changes that developers and the technology of that time required.

Just to mention a few of the new features:

  1. Read-only auto-properties
  2. Auto-property initializers
  3. Expression-bodied function members
  4. Using static
  5. Null-conditional operators

For a full list, see here.

In this guide, we will take a look at the null-conditional operators, more commonly referred to as null-propagation operators. There are also folks out there who refer to this feature as safe-navigation operator.

The Operators

In order to understand, we need to introduce two new operators. The main goal of these operators is to make code execution more fluid and replace the NullReferenceExeption with meaningful error handling.

  1. ?. -> Called member access operator
  2. ?[] -> Called element access operator

Let's look at an example of the member access operator. Before C#, the below code would have resulted in System.NullReferenceException: 'Object reference not set to an instance of an object.'

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
using System;
namespace Pluralsight
{
    public class NullProp
    {
        public static void Main()
        {
            Server DC = new Server();
            Console.WriteLine(DC.name.Length);
            Console.ReadKey();
        }
        class Server
        {
            public string name { get; set; }
        }
    }
}
csharp

The problem here is that we would like to check the length of a property that was never initialized, and this throws the exception.

One way to handle this is with the following modification of the code. We would like to wrap the critical code in a try - catch block looking for null references.

1
2
3
4
try 
    { Console.WriteLine(DC.name.Length); }
catch(System.NullReferenceException)
    { Console.WriteLine("The name is not initialized."); }
csharp

This gives us the following output.

1
The name is not initialized.
bash

This seems to do the trick, however, we need to modify the code as follows.

1
Console.WriteLine(DC?.name ?? "No Name provided yet!");
csharp

If we do not initialize the name property beforehand, we get the following output.

1
No Name provided yet!
bash

This saves us the try - catch block and reduces the code length. The ?? operator is called the null-coalescing operator, which allows us to write conditional expressions which return a default value when the expression evaluates to null. The ?. can be used to invoke a delegate in a thread-safe manner, which helps the development of multithreaded applications.

Note: This operator's nickname is the Elvis operator.

Let's see an example for the element access operator. We would like to modify the above code as follows.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
using System;
namespace Pluralsight
{
    public class NullProp
    {
        public static void Main()
        {
            Server[] servers = new Server[5];
            Server S1 = new Server();
            S1.name = "First";
            Server S2 = new Server();
            S2.name = "Second";
            Server S3 = new Server();            
            Server S4 = new Server();
            S4.name = "First";
            Server S5 = new Server();
            servers[0] = S1;
            servers[1] = S2;
            servers[2] = S3;
            servers[3] = S4;
            servers[4] = S5;
            foreach(Server s in servers)
            {
                Console.WriteLine(s?.name ?? "No Name specified!");
            }
            Console.ReadKey();
        }
        class Server
        {
            public string name { get; set; }
        }
    }
}
csharp

We need an array of five elements. This array will be filled with servers, and some servers will have their name properties initialized. Then we iterate over the servers and check with the member access operator if the servers' names are initialized. Okay, now you may be wondering where the demonstration is of the element access operator. The for loop can be easily converted to this type.

1
2
3
4
for(int i = 0; i < 5; i++)
{
    Console.WriteLine(servers?[i].name ?? "No name was specified!");
}
csharp

We can even combine the element and member access operators this way.

1
2
3
4
for(int i = 0; i < 5; i++)
{
    Console.WriteLine(servers?[i]?.name ?? "No name was specified!");
}
csharp

The following output is produced when we execute the code.

1
2
3
4
5
6
7
8
9
10
11
12
# first for loop
First
Second
No Name specified!
First
No Name specified!
# second for loop
First
Second
No name was specified!
First
No name was specified!
bash

Conclusion

The null-propagation operator represents a breaking point that brought resiliency to the C# programming language. It allows you to handle the System.NullReferenceException exception in a more elegant way. It also reduces the number of lines of code that need to be written and helps you avoid bugs further on. All in all, it makes code cleaner and easier to maintain. I hope this was informative to you, and I would like to thank you for reading it.

0