Click here to Skip to main content
15,884,917 members
Articles / Programming Languages / C#
Article

The Null Coalescing Operator (??)

Rate me:
Please Sign up or sign in to vote.
4.65/5 (26 votes)
28 Sep 2007CPOL2 min read 71.4K   24   25
One of the most useful yet little-known features to come out of C# 2.0

Introduction

I'm constantly surprised by the number of developers who aren't aware of this handy piece of syntax. It's my favourite thing to come out of C# 2.0 and no developer should be without it.

Like the conditional (?:) operator's big brother... introducing it for your coding pleasure...

The Null Coalescing Operator (??)

The null-coalescing-operator is a brilliant new terse operator that provides syntax for beautifully concise if statements. Essentially, it returns the left-hand-side of the ?? operator, unless null, in which case it executes and returns the right-hand-side of the operator. This may be a statement or a variable reference. Let's jump straight to some examples:

C#
// used inline outputs the value foo or if null returns Undefined
Console.WriteLine("The value of foo is " + (foo ?? "Undefined") + ".");
    
Input:  foo = "24";
Output: The value of foo is 24.
    
Input:  foo = null;
Output: The value of foo is Undefined.

The operator is right-associative meaning statements can be chained together; thus returning the first non-null instance:

C#
// assigns foo to the first non-null instance, else returns Undefined
string foo = foo1 ?? foo2 ?? foo3 ?? foo4 ?? "Undefined";
    
Console.WriteLine("The value of foo is " + foo + ".");

Input:  foo1 = null;
        foo2 = null;
        foo3 = null;
        foo4 = null;
Output: The value of foo is Undefined.
    
Input:  foo1 = null;
        foo2 = "foo2";
        foo3 = null;
        foo4 = "foo4";
Output: The value of foo is foo2.

Handling null ViewState references:

C#
// try to assign ViewState value as an int, else if null assign 123
int foo = (int?)ViewState["foo"] ?? 123;
    
Response.Write("The value of foo is " + foo + ".");
    
Input:  ViewState["foo"]=1;
Output:  The value of foo is 1.  
    
Input:  ViewState["foo"]=null;
Output:  The value of foo is 123.  

And my personal favorite, on demand field instantiation:

C#
private IList<string> foo;

public IList<string> Foo
{
    get
    {
        return foo ?? (foo = new List<string>());
    }
}

Here's an interesting example derived from an idea in the discussions below. It shows how an operator override can be used within an object's definition to enable shorthand syntax for double-null checking. The scenario is checking an object property for null using a null-coalescing-operator, but also defaulting when null-object-reference occurs; which would normally cause a runtime exception. (Note that I don't recommend actually using this approach, I just thought it made an interesting example.)

C#
public class Address
{
    private static Address Empty = new Address();
    public string StreetName = null;
    
    public static Address operator +(Address address)
    {
        return address ?? Empty
    }
}
  
Console.WriteLine("The street name is "+ (+address).StreetName ?? "n/a" + ".");
  
Input:  address = new Address();
Output:  The street name is n/a.  
    
Input:  address = new Address();
            address.StreetName = "Regent St";
Output:  The street name is Regent St.    
    
Input:  address = null;
Output:  The street name is n/a.

The Rules

To use the null-coalescing-operator, there are some compile-time ground rules.

  • The left-hand-side must evaluate to a reference or nullable type.
  • All evaluated statements must be of matching type, unless they can be implicitly converted.

Summary

As you can see from the examples above, this little gem is very powerful and the possibilities are endless. Of course the benefits are purely syntactical, but it helps keep the code clean and easier to follow. I hope you enjoy it as much as I do.

History

  • 28th September, 2007: Initial post

License

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


Written By
Architect
United Kingdom United Kingdom
Mike Carlisle - Technical Architect with over 20 years experience in a wide range of technologies.

@TheCodeKing

Comments and Discussions

 
QuestionShow null value in check out column Pin
Mohammad Imran13-Jan-24 0:35
Mohammad Imran13-Jan-24 0:35 
GeneralAn alternate view Pin
Big Al 071-Oct-07 6:38
Big Al 071-Oct-07 6:38 
GeneralRe: An alternate view Pin
TheCodeKing1-Oct-07 8:18
TheCodeKing1-Oct-07 8:18 
GeneralRe: An alternate view Pin
Hal Angseesing1-Oct-07 9:06
professionalHal Angseesing1-Oct-07 9:06 
GeneralRe: An alternate view Pin
Big Al 071-Oct-07 14:47
Big Al 071-Oct-07 14:47 
Hi CodeKing
Ended up … long winded… sorry!

I agree less lines of code leads to less bugs... but that is a volume thing... i.e. zero lines means no bugs, thousands of lines means many bugs! Many things drive quantity of bugs ranging from requirements analysis, software architecture all the way down to quality of written lines of code. And yes, even the compiler and sometimes even processor microcode!

The following lines of code are reasonably concise – but probably load of B***cks, because I've not spent any time on it, but does serve to illustrate how I feel about it. I claim no correctness here, just an illustration…

WheelsDown = TrySenseGearDown();
etc
WarningLightOn = !WheelsDown ?? true && (RadarAltitude - RadarAccuracy ?? LastRadarAltitude – RadarAccuracy-200 ?? PressureAltEstimate - PressureAccuracy ?? 0) < 500;

Personally I would just feel a bit more comfortable to fly in something if this was coded in a bit more long hand and spelt out. Why do I feel this way – I think a competent coder writing it longhand (spelt out) is less likely to have bugs, and more importantly someone coming along later (possibly less competent) is less likely to add bugs.

If I feel this way about such an important “application”(!) then I should also professionally feel the same way about any production code I write. It’s a viewpoint that’s all. For me, after a few years of C and C++ I do not accept that terseness should necessarily be taken as a good thing for its own sake – especially when it’s someone else’s codeSigh | :sigh: Fine, when fast code is needed (say drivers, audio processing, graphics etc), but all I’m saying is that’s not what I want or expect from C#.

A competent optimising compiler should have a pretty good stab at optimising the longhand anyway. If not, and that important, I would suggest dropping down a level to C++, C or Assembler depending on your tastes.

I apologise if this seems “old school” (bit below the belt I feel – shame on you!)… one of the projects I worked on was team leader for the Right 3 computers flying the Boeing 777. This sharpens the mind somewhat and makes you try to make everything very obvious, spelt out and easily maintainable.

Also, your hint at “old school” is true. Started coding assembler in 1978, and coded many languages and app domains since and still feel I’m working on some leading edge stuff .NET 3, now 3.5 WPF, Workflow, LINQ etc and own a SW house of 40 people. In that, I don’t mind being considered “old School”!

You did say “I agree they shouldn't be thrown in without due care and attention” and actually I agree – but in moderation. The provision of terse operators can easily be abused by someone who can see them as a measure of their cleverness. Finally, this is not a big issue! It’s not the operator I mind, so much as the statement implying that “terse is better”… that I cannot agree with.
GeneralRe: An alternate view Pin
kschulz1-Oct-07 12:08
kschulz1-Oct-07 12:08 
GeneralRe: An alternate view Pin
Matware1-Oct-07 16:24
Matware1-Oct-07 16:24 
GeneralRe: An alternate view Pin
greenblob3-Oct-07 5:12
greenblob3-Oct-07 5:12 
GeneralRe: An alternate view Pin
Rei Miyasaka18-Oct-07 19:06
Rei Miyasaka18-Oct-07 19:06 
GeneralRe: An alternate view Pin
peterchen5-Jan-08 10:25
peterchen5-Jan-08 10:25 
GeneralThis thing existed?! Pin
Rei Miyasaka29-Sep-07 9:12
Rei Miyasaka29-Sep-07 9:12 
GeneralThanks Pin
Lutosław29-Sep-07 0:19
Lutosław29-Sep-07 0:19 
GeneralA handy operator Pin
chaiguy133728-Sep-07 11:50
chaiguy133728-Sep-07 11:50 
GeneralRe: A handy operator Pin
Daniel Grunwald28-Sep-07 12:30
Daniel Grunwald28-Sep-07 12:30 
GeneralRe: A handy operator Pin
chaiguy133728-Sep-07 13:01
chaiguy133728-Sep-07 13:01 
GeneralRe: A handy operator Pin
Daniel Grunwald29-Sep-07 0:18
Daniel Grunwald29-Sep-07 0:18 
GeneralRe: A handy operator Pin
TheCodeKing28-Sep-07 13:09
TheCodeKing28-Sep-07 13:09 
GeneralRe: A handy operator [modified] Pin
TheCodeKing28-Sep-07 13:24
TheCodeKing28-Sep-07 13:24 
GeneralRe: A handy operator Pin
TheCodeKing28-Sep-07 12:42
TheCodeKing28-Sep-07 12:42 
GeneralRe: A handy operator Pin
TheCodeKing28-Sep-07 12:44
TheCodeKing28-Sep-07 12:44 
GeneralRe: A handy operator Pin
chaiguy133728-Sep-07 12:56
chaiguy133728-Sep-07 12:56 
GeneralRe: A handy operator Pin
TheCodeKing28-Sep-07 13:02
TheCodeKing28-Sep-07 13:02 
GeneralRe: A handy operator Pin
JoshuaMcKinney6-Oct-07 20:39
JoshuaMcKinney6-Oct-07 20:39 
GeneralRe: A handy operator Pin
chaiguy13378-Oct-07 7:42
chaiguy13378-Oct-07 7:42 
GeneralRe: A handy operator Pin
TheCodeKing8-Oct-07 8:17
TheCodeKing8-Oct-07 8:17 

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.