You cannot use a null propagating operator in an expression tree lambda

One of the features I like about the new C# 6.0 is the null conditional operator, and I tend to use it everywhere I can (and should). Until yesterday, when at a statement I wasn’t expecting it, the compiler bit me with error CS8072, An expression tree lambda may not contain a null propagating operator. If you think about it, it makes sense, but it is easy to miss.

Null conditional operator?

For those few unfamiliar with this operator, also called a null propagating operator, in short (pun intended) it is about making your code less verbose when checking for null if you need to access an object’s properties. Before, you would write something like this:

public string DoSomething (string value) {
    if (value != null) {
        return value.Substring(10,20);
    }
    return null;
}

Using the existing conditional operator, this could already be shortened to:

return value != null ? value.Substring(10,20) : null;

But that is still a bit verbose and readability could be better. The new C# 6 null conditional operator ?. allows you to write:

return value?.Substring(10,20);

Which will give the same results as the statements above: null if value is null, or its substring if it isn’t. It is shorter, more readable and better understandable with the code does. As a bonus it is even evaluated only once instead of twice.

But you cannot use it everywhere

In a project using C# 6 and Entity Framework, I wrote (example) something like the following service method to return an OrderDetail domain object, selected from a datasource.

using (var context = CreateDbContext()) {
    return (
        from o in context.Orders 
        where o.ID == value 
        select new OrderDetail {
            OrderID = o.ID,
            OrderDateText = o.OrderDate != null ? o.OrderDate.Value.ToString("ddd dd-MM") : String.Empty
        }).SingleOrDefault();
}

That compiles fine, but I spotted an opportunity to use my new pet operator. So I rewrote the line for OrderDateText.

OrderDateText = o.OrderDate?.ToString("ddd dd-MM") ?? String.Empty

Better, right? Well, no.

Error CS8072: An expression tree lambda may not contain a null propagating operator.

Why can I do the first and not the last? It is because this expression does not remain C# code. The LINQ expression gets translated into SQL by the EF provider, and this provider does not support the new operator. Support for this operator is already being discussed, but for now, we’re out of luck on this one.

There are several ways to work around this, each with slightly different effects. I wanted to use the operator badly, so this is what I did at first:

var result = context.orders.SingleOrDefault(o => o.ID == value);
return result == null ? null : new OrderDetail {
            OrderID = o.ID,
            OrderDateText = o.OrderDate?.ToString("ddd dd-MM") ?? String.Empty
}

By moving the code with the operator out of the expression, you can keep using it. The downside is that the generated SQL is bit less efficient because it will return all columns instead of only the required ones. I could argue it was ok for this situation, because I was only requesting a single row and was in fact using almost all columns anyway (example above is simplified) and I preferred the readability over performance.

The best solution, performance-wise, is to keep using the original construct and don’t use the null conditional operator situations like this. But even if the compiler doesn’t complain, it may fail on you at runtime.

Advertenties

Over Shiftkey
I am Maarten, owner of and chief software developer for Shiftkey software development from The Netherlands. I will be writing mainly about things I run into when programming in C# or Delphi.

2 Responses to You cannot use a null propagating operator in an expression tree lambda

  1. Zev Spitz says:

    This isn’t quite accurate. The compiler cannot compile the null-propagation operator into an expression. This is much before the EF provider sees the resultant expression, which is at runtime. In fact, it wouldn’t matter which provider was being used. (This is unlike calling .ToString within an expression, which the compiler can successfully handle, but EF doesn’t know how to convert the ToString call to SQL.)

Geef een reactie

Vul je gegevens in of klik op een icoon om in te loggen.

WordPress.com logo

Je reageert onder je WordPress.com account. Log uit / Bijwerken )

Twitter-afbeelding

Je reageert onder je Twitter account. Log uit / Bijwerken )

Facebook foto

Je reageert onder je Facebook account. Log uit / Bijwerken )

Google+ photo

Je reageert onder je Google+ account. Log uit / Bijwerken )

Verbinden met %s

%d bloggers liken dit: