Click here to Skip to main content
14,303,059 members

Null-Conditional Operator in C# 6.0

Rate this:
5.00 (8 votes)
Please Sign up or sign in to vote.
5.00 (8 votes)
8 Apr 2016CPOL
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, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Dmitry Zinchenko
United States United States
I am a software developer who likes to learn new technologies.

Comments and Discussions

 
PraisePresentation Pin
Eugene Sadovoi16-Apr-16 2:47
memberEugene Sadovoi16-Apr-16 2:47 
GeneralRe: Presentation Pin
Dmitry Zinchenko20-Apr-16 1:25
memberDmitry Zinchenko20-Apr-16 1:25 
QuestionRobust is a matter of doing it right Pin
Rolf Borchmann11-Apr-16 21:28
memberRolf Borchmann11-Apr-16 21:28 
AnswerRe: Robust is a matter of doing it right Pin
Dmitry Zinchenko12-Apr-16 2:38
memberDmitry Zinchenko12-Apr-16 2:38 
GeneralRe: Robust is a matter of doing it right Pin
Rolf Borchmann12-Apr-16 9:36
memberRolf Borchmann12-Apr-16 9:36 
GeneralRe: Robust is a matter of doing it right Pin
Dmitry Zinchenko13-Apr-16 16:31
memberDmitry Zinchenko13-Apr-16 16:31 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Article
Posted 8 Apr 2016

Tagged as

Stats

16.2K views
4 bookmarked