Compsoft Flexible Specialists

Compsoft plc

Compsoft Weblog Compsoft Website News Archive Privacy Policy Contact Us  

Monday, July 20, 2009

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?

0 Comments:

Post a Comment

<< Home