?. in C#: When properties might be null

The more I work with C# 6 in projects, the more I find myself using ?. to write cleaner, simpler, and more readable code.  Here are four different uses I’ve found for the null coalescing operator.

Deep Containment Designs

Suppose I’m writing code that needs to find the street location for the home address for a contact person for vendor. Maybe there’s an awesome event, and I need to program my GPS. Using earlier versions of C#, I’d need to write a staircase of if statements checking each property along the way:

 

var location = default(string);

if (vendor != null)

{

    if (vendor.ContactPerson != null)

    {

        if (vendor.ContactPerson.HomeAddress != null)

        {

            location = vendor.ContactPerson.HomeAddress.LineOne;

        }

    }

}

 

Now, using C# 6, this same idiom becomes much more readable:

 

var location = vendor?.ContactPerson?.HomeAddress?.LineOne;

 

The null coalescing operator short-circuits, so evaluation stops as soon as any single property evaluates as null.

INotifyPropertyChanged and similar APIs

We’ve all seen code like this in a class the implements INotifyPropertyChanged:

 

public string Name {

    get { return name;  }

    set {

        if (name != value)

        {

            name = value;

            PropertyChanged(this, new PropertyChangedEventArgs("Name"));

        }

    }

}

private string name;

 

I hope your are cringing now. This code will crash if it’s used in a situation where no code subscribes to the INotifyPropertyChanged.PropertyChanged event. It raises that event even when there are no listeners. 

When faced with that situation, many developers write something like the following:

 

public string Name {

    get { return name;  }

    set {

        if (name != value)

        {

            name = value;

            if (PropertyChanged != null)

                PropertyChanged(this, new PropertyChangedEventArgs("Name"));

        }

    }

}

private string name;

 

OK, this is a little better, and will likely work in most production situations. However, there is a possible race condition lurking in this code. If a subscriber removes a handler between the ‘if’ check and the line that raises the event, this code can still crash. It’s the kind of insidious bug that may only show up months after deploying an application.  The proper fix is to create a temporary reference to the existing handler, and raise the event on that object rather than allowing the race condition on the PropertyChanged public event:

 

public string Name {

    get { return name;  }

    set {

        if (name != value)

        {

            name = value;

            var handler = PropertyChanged;

            if (handler != null)

                handler(this, new PropertyChangedEventArgs("Name"));

        }

    }

}

private string name;

 

It’s more code, and it’s a few different techniques to remember every time you raise the PropertyChanged event. In a large program, it seems like someone forgets at least once.

C# 6 to the rescue!

In C# 6, the null coalescing operator implements all the checks I mentioned above. You can replace the extra checks, and the local variable with a ?. and a call to Invoke:

 

public string Name {

    get { return name;  }

    set {

        if (name != value)

        {

            name = value;

            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Name"));

        }

    }

}

private string name;

 

The shorter, more modern version reads more concisely, and implements the proper idioms for raising events and managing subscribers being added or removed.

Resource Management

Occasionally, we may find that one of our types owns another object that has certain capabilities. However, that object may implement other capabilities beyond those our class requires. Usually, that’s not an issue, but what if that object implements IDisposable? Consider the case of an Evil Genius that is done working with a henchman.  The code to retire a henchman might look like this:

 

public void RetireHenchman()

{

    var disposableMinion = Minion as IDisposable;

    if (disposableMinion != null)

        disposableMinion.Dispose();

    Minion = null;

}

 

The null coalescing operator can make this code more concise as well:

 

public void RetireHenchman()

{

    (Minion as IDisposable)?.Dispose();

    Minion = null;

}

 

LINQ Queries

There are two different uses I’ve found for this operator when I work with LINQ queries.  One very common use if after I create a query that uses SingleOrDefault(). I’ll likely want to access some property of the (possible) single object. That’s simple with ?.

 

var created = members.SingleOrDefault(e => e.name == "dateCreated")?.content;

 

Another use is to create a null output whenever the input sequence is null:

 

members?.Select(m => (XElement)XmlValue.MakeValue(m))

 

The addition of this feature has made me realize just how much code checks for null, and how much more concise and readable our code will be by having a more concise syntax for checking against null, and taking some default action based on the ‘null-ness’ of a variable.

This feature has changed how I code everyday. I can’t wait for the general release and getting more of my customers to adopt the new version.

Created: 3/3/2015 4:34:42 PM

Current Projects

I create content for .NET Core. My work appears in the .NET Core documentation site. I'm primarily responsible for the section that will help you learn C#.

All of these projects are Open Source (using the Creative Commons license for content, and the MIT license for code). If you would like to contribute, visit our GitHub Repository. Or, if you have questions, comments, or ideas for improvement, please create an issue for us.

I'm also the president of Humanitarian Toolbox. We build Open Source software that supports Humanitarian Disaster Relief efforts. We'd appreciate any help you can give to our projects. Look at our GitHub home page to see a list of our current projects. See what interests you, and dive in.

Or, if you have a group of volunteers, talk to us about hosting a codeathon event.