Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Null-Conditional Operator in C# 6.0

0.00/5 (No votes)
8 Apr 2016 1  
Null-conditional operator in C# 6.0 is not just a mere convenient syntactic sugar.

Introduction

If you’ve read blog posts or even MSDN articles explaining new features in C# 6.0 – I’m sure you’ve learned that the null-conditional operator in C# 6.0 will help you to greatly reduce the number of hard-to-debug and hard-to-reproduce NullReferenceException-s.

When I first read about this operator, the only thing that registered in my mind was that it helped you to chain null checks, especially for descending into data structures, and short-circuit the rest of the checks as soon as you hit null somewhere in the chain. So, I thought it was just a mere convenient syntactic sugar.

But I still did not completely understand the true power of this operator. I’m usually pretty meticulous about null checks and have a lot of C# 5.0 code like this:

// C# 5.0 code    
private static int GetCurrentSpeed(Car car)
{
    if (car != null && car.Engine != null && car.Engine.ControlUnit != null)
    {
        return car.Engine.ControlUnit.CurrentSpeed;
    }
 
    return 0;
}

And I was debating whether it was worth it to go through the code base and refactor it to use null-conditional operator. Would I gain anything? Was it worth it just to have the code to look like this:

// C# 6.0 code    
private static int GetCurrentSpeed(Car car)
{
    return car?.Engine?.ControlUnit?.CurrentSpeed ?? 0;
}    

Okay, I cut 5 lines of code, what’s the big deal?

One day I was watching Pluralsight course Exploring C# 6 with Jon Skeet (fast forward to 3:40) and I finally got the answer, which actually was in plain sight in the MSDN article:

Quote:

The new way is thread-safe because the compiler generates code to evaluate a property one time only, keeping the result in temporary variable.

As much as it became clear to me, I still wanted to see what’s going on. As they say – “A picture is worth thousand words”. What is the best picture? Of course the picture of IL code:). So, I created these simple models:

namespace CS6
{
    public class ControlUnit
    {
        public int CurrentSpeed { get; set; } 
    }
 
    public class Engine
    {
        public ControlUnit ControlUnit { get; set; } 
    }
 
    public class Car
    {
        public Engine Engine { get; set; }
    }
}

and two console applications – one in VS2013 (C# 5.0) and another in VS2015 (C# 6.0), the ones that are shown in the previous code snippets. (Note: In VS2015, in project properties, you can specify what version of C# compiler to target). Then I used JetBrains dotPeek to see what IL code was created by each of the compilers.

IL Generated By C# 5.0

IL Generated by C# 5.0

You can click on the image and see the code and IL side-by-side, but you might prefer a C# 5.0 Program and IL Gist.

If you look at the C# 5.0 code line 13, the code that accesses car.Engine property, has corresponding get_Engine() invocation (line 59 in IL). Similarly, code on the same line that accesses car.Engine.ControlUnit property has corresponding get_Engine() and get_ControlUnit() invocations (lines 62 and 63 in IL).

The car.Engine.ControlUnit.CurrentSpeed property access code on line 15 has corresponding invocations of get_Engine(), get_ControlUnit() and get_CurrentSpeed() on lines 79 through 81.

The problem with this code is that at any time the thread it is running on can be preempted and another thread can assign a null value to the previously checked property. When the control is yielded back to the original thread and you access that property – the hard-to-debug and hard-to-reproduce NullReferenceException will be thrown.

IL Generated By C# 6.0

IL Generated by C# 6.0

You can click on the image and see the code and IL side-by-side, but you might prefer a C# 6.0 Program and IL Gist.

If you look at the C# 6.0 code line 13, the code that uses null-conditional operator to access three properties has only three corresponding calls to get_Engine(), get_ControlUnit() and get_CurrentSpeed() (lines 64, 72 and 80 in IL) producing far more robust code.

Conclusion

We finally got an excellent feature to prevent NullReferenceException in our code and you should move your code base to C# 6.0 as soon as possible!

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here