Null-Conditional Operator in C# 6.0

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 understood 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:

“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

post-12-CS5

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

post-12-CS6

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!

Null-Conditional Operator in C# 6.0

2 thoughts on “Null-Conditional Operator in C# 6.0

  1. Thank you, very interesting article. Its allways nice to be able to prove the feature is useful not only using this reason: look its lloks and feel nice, which is subjective.

Comments are closed.