Click here to Skip to main content
15,885,741 members
Articles / Programming Languages / C# 6.0

?. in C#: When Properties Might Be Null

Rate me:
Please Sign up or sign in to vote.
4.59/5 (16 votes)
17 Dec 2015CPOL3 min read 15.9K   16   8
?. 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:

C#
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:

C#
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:

C#
public string Name {
    get { return name;  }
    set {
        if (name != value)
        {
            name = value;
            PropertyChanged(this, new PropertyChangedEventArgs("Name"));
        }
    }
}
private string name;

I hope you 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:

C#
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:

C#
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:

C#
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:

C#
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:

C#
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 ?.

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

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

C#
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.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect Bill Wagner Software LLC
United States United States
Bill Wagner is one of the world's foremost C# developers and a member of the ECMA C# Standards Committee. He is President of the Humanitarian Toolbox, has been awarded Microsoft Regional Director and .NET MVP for 10+years, and was recently appointed to the .NET Foundation Advisory Council. Wagner currently works with companies ranging from start-ups to enterprises improving the software development process and growing their software development teams.

Comments and Discussions

 
GeneralEquivalent for non-C#6 coders Pin
Michael D Bray19-Jan-16 3:56
Michael D Bray19-Jan-16 3:56 
QuestionNull coalescing operator?? Pin
Member 323083920-Dec-15 1:00
Member 323083920-Dec-15 1:00 
Questionfunctional decomposition Pin
Member 1202398818-Dec-15 18:20
Member 1202398818-Dec-15 18:20 
AnswerMessage Closed Pin
16-Jan-16 1:49
Member 1089184816-Jan-16 1:49 
PraiseNice Tip Pin
L Viljoen18-Dec-15 2:52
professionalL Viljoen18-Dec-15 2:52 
QuestionOne of the greatest additions to the language Pin
Siderite Zackwehdex18-Dec-15 0:15
Siderite Zackwehdex18-Dec-15 0:15 
QuestionNotifyPropertyChanged Pin
Michel Renaud17-Dec-15 8:57
Michel Renaud17-Dec-15 8:57 
AnswerRe: NotifyPropertyChanged Pin
Siderite Zackwehdex18-Dec-15 0:12
Siderite Zackwehdex18-Dec-15 0:12 
GeneralRe: NotifyPropertyChanged Pin
Member 1202398818-Dec-15 18:30
Member 1202398818-Dec-15 18:30 

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.