2

I'd like to generate this sentence using Expression trees:

o?.Value

o is an instance of whichever class.

Is there some way?

svick
  • 236,525
  • 50
  • 385
  • 514
Jordi
  • 20,868
  • 39
  • 149
  • 333

1 Answers1

9

Normally, if you want to know how to construct an expression tree for some expression, you let the C# compiler do it and inspect the result.

But in this case, it won't work, because "An expression tree lambda may not contain a null propagating operator." But you don't actually need the null propagating operator, you just need something that behaves like one.

You can do that by creating an expression that looks like this: o == null ? null : o.Value. In code:

public Expression CreateNullPropagationExpression(Expression o, string property)
{
    Expression propertyAccess = Expression.Property(o, property);

    var propertyType = propertyAccess.Type;

    if (propertyType.IsValueType && Nullable.GetUnderlyingType(propertyType) == null)
        propertyAccess = Expression.Convert(
            propertyAccess, typeof(Nullable<>).MakeGenericType(propertyType));

    var nullResult = Expression.Default(propertyAccess.Type);

    var condition = Expression.Equal(o, Expression.Constant(null, o.Type));

    return Expression.Condition(condition, nullResult, propertyAccess);
}
svick
  • 236,525
  • 50
  • 385
  • 514
  • 2
    Just like `o == null ? null : o.Value`, and unlike `o?.Value`, this would cause `o` to be evaluated twice if compiled to IL, right? If so, that should probably be mentioned. –  Sep 21 '16 at 13:15
  • 3
    @hvd Yes. I was silently assuming it's okay, since evaluating a simple expression like `o` twice should not cause any issues. If you wanted to avoid that, you could create a `Block` that first assigns `o` to a temporary variable and then uses that variable. (Though that would probably not work if you want to use the expression with some LINQ provider.) – svick Sep 21 '16 at 13:37
  • You has commented that _if you want to do how to construct an expression tree for some expression, you let the C# compiler do it and inspect the result_. I'd like to ask you for how to inspect these. – Jordi Sep 23 '16 at 07:51
  • @Jordi By looking at it in the debugger. You could also try converting it to a string (e.g. `Console.WriteLine(expression);`), but the result might not tell you much (e.g. `IIF((o == null), null, o.Value)`). – svick Sep 23 '16 at 11:39
  • 3
    Unfortunately, this implementation is not actually equivalent to the null-conditional operator. The actual C# operator will retrieve the possibly-null expression once, and then use that throughout. This makes it, for example, perfectly suited for raising C# events in a thread-safe way. IMHO it is erroneous and dangerous to provide a proposed implementation for the operator that doesn't have the same behavior as the actual operator. – Peter Duniho Jul 18 '19 at 17:29