C# coalesce operator (double question mark) gotcha
I'm sure you've met the C# coalesce operator, where you can use a double question mark to check for null:
x = y ?? z;
... being equivalent to:
if (y != null)x = y;else
x = z;
It's a handy shortcut, but sometimes it doesn't behave quite as you I might expect.
Here's an example:
I wanted to combine the elements of an address to make a field that was searchable with a SQL LIKE statement. As we use LINQ to SQL, I needed an expression that LINQ to SQL could translate into SQL syntax. I wrote this:
...select new
{SearchableAddress = c.Address.HouseName ?? "" + " "
+ c.Address.HouseNumber ?? "" + " "
+ c.Address.Road ?? "" + " "
+ c.Address.Town ?? "" + " "
+ c.Address.County ?? "" + " "
+ c.Address.Postcode ?? ""}
I'm using the coalesce operator to replace nulls with empty strings - otherwise SQL returns NULL for the whole expression if a single element is NULL.
However, I found my search was rarely getting any matches, and a little digging isolated the above expression as the culprit.
It turns out that the coalesce operator takes lower precedence than the concatenation operator. What I meant (and what I should have written) was this:
...select new
{SearchableAddress = (c.Address.HouseName ?? "") + " "
+ (c.Address.HouseNumber ?? "") + " "
+ (c.Address.Road ?? "") + " "
+ (c.Address.Town ?? "") + " "
+ (c.Address.County ?? "") + " "
+ (c.Address.Postcode ?? "")}
... but my version without any parentheses was equivalent to this:
...select new
{SearchableAddress = c.Address.HouseName ??("" + " " + c.Address.HouseNumber) ??
("" + " " + c.Address.Road) ??
("" + " " + c.Address.Town) ??
("" + " " + c.Address.County) ??
("" + " " + c.Address.Postcode) ??
""}
Getting back the first non-null element, padded with a superfluous space, was enough to make the search work occasionally enough to be confusing.
Maybe I should have seen it coming, as I'd happily use:
a = b ?? c ?? d ?? e;
to get the first non-null value, but that string concatenation threw me off the scent.
I dunno - to me coalesce feels like a unary operator, so I'd expect it to be evaluated first; it turns out it gets evaluated almost last. What do you think?