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:

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:

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

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

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