Unique ways to use the null coalescing operator

Viewed 70594

I know the standard way of using the null coalescing operator in C# is to set default values.

string nobody = null;
string somebody = "Bob Saget";
string anybody = "";

anybody = nobody   ?? "Mr. T"; // Returns Mr. T
anybody = somebody ?? "Mr. T"; // Returns "Bob Saget"

But what else can ?? be used for? It doesn't seem as useful as the ternary operator, apart from being more concise and easier to read than:

nobody = null;
anybody = nobody == null ? "Bob Saget" : nobody; // Returns Bob Saget

So given that fewer even know about null coalescing operator...

  • Have you used ?? for something else?

  • Is ?? necessary, or should you just use the ternary operator (that most are familiar with)

16 Answers

Well, first of all, it's much easier to chain than the standard ternary operator:

string anybody = parm1 ?? localDefault ?? globalDefault;

vs.

string anyboby = (parm1 != null) ? parm1
               : ((localDefault != null) ? localDefault
               : globalDefault);

It also works well if a null-possible object isn't a variable:

string anybody = Parameters["Name"]
              ?? Settings["Name"]
              ?? GlobalSetting["Name"];

vs.

string anybody = (Parameters["Name"] != null ? Parameters["Name"]
                 : (Settings["Name"] != null) ? Settings["Name"]
                 :  GlobalSetting["Name"];

I've used it as a lazy load one-liner:

public MyClass LazyProp
{
    get { return lazyField ?? (lazyField = new MyClass()); }
}

Readable? Decide for yourself.

I've found it useful in two "slightly odd" ways:

  • As an alternative for having an out parameter when writing TryParse routines (i.e. return the null value if parsing fails)
  • As a "don't know" representation for comparisons

The latter needs a little bit more information. Typically when you create a comparison with multiple elements, you need to see whether the first part of the comparison (e.g. age) gives a definitive answer, then the next part (e.g. name) only if the first part didn't help. Using the null coalescing operator means you can write pretty simple comparisons (whether for ordering or equality). For example, using a couple of helper classes in MiscUtil:

public int Compare(Person p1, Person p2)
{
    return PartialComparer.Compare(p1.Age, p2.Age)
        ?? PartialComparer.Compare(p1.Name, p2.Name)
        ?? PartialComparer.Compare(p1.Salary, p2.Salary)
        ?? 0;
}

Admittedly I now have ProjectionComparer in MiscUtil, along with some extensions, which make this kind of thing even easier - but it's still neat.

The same can be done for checking for reference equality (or nullity) at the start of implementing Equals.

Another advantage is that the ternary operator requires a double evaluation or a temporary variable.

Consider this, for instance:

string result = MyMethod() ?? "default value";

while with the ternary operator you are left with either:

string result = (MyMethod () != null ? MyMethod () : "default value");

which calls MyMethod twice, or:

string methodResult = MyMethod ();
string result = (methodResult != null ? methodResult : "default value");

Either way, the null coalescing operator is cleaner and, I guess, more efficient.

I've used ?? in my implementation of IDataErrorInfo:

public string Error
{
    get
    {
        return this["Name"] ?? this["Address"] ?? this["Phone"];
    }
}

public string this[string columnName]
{
    get { ... }
}

If any individual property is in an "error" state I get that error, and otherwise I get null. It works really well.

Is ?? necessary, or should you just use the ternary operator (that most are familiar with)

Actually, my experience is that all too few people are familiar with the ternary operator (or more correctly, the conditional operator; ?: is "ternary" in the same sense that || is binary or + is either unary or binary; it does however happen to be the only ternary operator in many languages), so at least in that limited sample, your statement fails right there.

Also, as mentioned before, there is one major situation when the null coalescing operator is very useful, and that is whenever the expression to be evaluated has any side effects at all. In that case, you cannot use the conditional operator without either (a) introducing a temporary variable, or (b) changing the actual logic of the application. (b) is clearly not appropriate in any circumstances, and while it's a personal preference, I don't like cluttering up the declaration scope with lots of extraneous, even if short-lived, variables, so (a) is out too in that particular scenario.

Of course, if you need to do multiple checks on the result, the conditional operator, or a set of if blocks, are probably the tool for the job. But for simple "if this is null, use that, otherwise use it", the null coalescing operator ?? is perfect.

The only problem is the null-coalesce operator doesn't detect empty strings.


I.e.

string result1 = string.empty ?? "dead code!";

string result2 = null ?? "coalesced!";

Output

result1 = ""

result2 = coalesced!

I'm currently looking into overriding the ?? operator to work around this. It sure would be handy to have this built into the framework.

Is ?? necessary, or should you just use the ternary operator (that most are familiar with)

You should use what best expresses your intent. Since there is a null coalesce operator, use it.

On the other hand, since it's so specialized, I don't think it has other uses. I would have preferred an appropriate overload of the || operator, as other languages do. This would be more parsimonious in the language design. But well …

Cool! Count me as someone who didn't know about the null coalescing operator -- that's pretty nifty stuff.

I find it much easier to read than the ternary operator.

The first place that comes to mind where I might use it is to keep all of my default parameters in a single place.

public void someMethod(object parm2, ArrayList parm3)
{
  someMethod(null, parm2, parm3);
}

public void someMethod(string parm1, ArrayList parm3)
{
  someMethod(parm1, null, parm3);
}

public void someMethod(string parm1, object parm2)
{
  someMethod(parm1, parm2, null);
}

public void someMethod(string parm1)
{
  someMethod(parm1, null, null);
}

public void someMethod(object parm2)
{
  someMethod(null, parm2, null);
}

public void someMethod(ArrayList parm3)
{
  someMethod(null, null, parm3);
}

public void someMethod(string parm1, object parm2, ArrayList parm3)
{
  // Set your default parameters here rather than scattered 
  // through the above function overloads
  parm1 = parm1 ?? "Default User Name";
  parm2 = parm2 ?? GetCurrentUserObj();
  parm3 = parm3 ?? DefaultCustomerList;

  // Do the rest of the stuff here
}

I have used it like this:

for (int i = 0; i < result.Count; i++)
{
    object[] atom = result[i];

    atom[3] = atom[3] ?? 0;
    atom[4] = atom[4] != null ? "Test" : string.Empty;
    atom[5] = atom[5] ?? "";
    atom[6] = atom[6] ?? "";
    atom[7] = atom[7] ?? "";
    atom[8] = atom[8] ?? "";
    atom[9] = atom[9] ?? "";
    atom[10] = atom[10] ?? "";
    atom[12] = atom[12] ?? false;
}
Related