5

Let's say, I have following simplified type:

public class Model
{
    public decimal? Result { get; set; }
}

How to express null coalescing operator using CodeDOM to generate C# code, is it possible at all? Now I'm using following workaround:

new CodePropertyReferenceExpression(
    new CodePropertyReferenceExpression(modelArgument, "Result"),
        "Value"))

Which is equal to model.Result.Value, but not model.Result ?? 0M

Better workaround

CodeExpression equalent to model.Result.GetValueOrDefault(0M) suitable for nullable value types

new CodeMethodInvokeExpression(
                        new CodeMethodReferenceExpression(
                            new CodePropertyReferenceExpression(modelArgument, "Result"),
                            "GetValueOrDefault"),
                            new [] { new CodePrimitiveExpression(0m) })),
Community
  • 1
  • 1
Akim
  • 8,469
  • 2
  • 31
  • 49
  • Just a thought, Have you tried just coding a simply POCO with a null-coalescing operator and looking at the code that's generated in IL-Dasm or reflector ? – Russ Clarke Apr 10 '13 at 22:55
  • @RussC I tried it out. The generated IL of `model.Result ?? 0M` is identical to `model.Result.HasValue ? model.Result.GetValueOrDefault() : 0M` – p.s.w.g Apr 10 '13 at 23:01
  • I thought that might be the case; the null coalesce is just a compiler trick then; that should give you a better clue on what to emit. From what I've read, instead of making a emitting a ternary operator (which seems to be disallowed) emit an If..Else block. – Russ Clarke Apr 10 '13 at 23:07
  • That's based on this link: http://www.pcreview.co.uk/forums/can-ternary-conditional-expressions-represented-codedom-t3154907.html – Russ Clarke Apr 10 '13 at 23:08
  • 1
    Why don't you simply use `model.Result.GetValueOrDefault()`? Or do you also need to support other default values? – svick Apr 10 '13 at 23:21
  • It is also possible to have `model.Result.GetValueOrDefault(10m)` where `10m` is custom default value – Akim Apr 11 '13 at 08:07

1 Answers1

3

As guys mentioned in the comment section, ?? operator is just a syntactical sugar. If you inspect IL code you will see condition on HasValue and then call to a GetValueOrDefault method. This method accepts a parameter, that will be returned if a Nullable object has no value, in other case it will return Value property.

Try to use next code, that simply call GetValueOrDefault method via CodeMethodInvokeExpression, which is semantically equivalent to the call of null-coallesing operator. I use 4 as a default value, but in you case omiting the parameter will do the job, because you demand 0m as a default value for a decimal.

new CodeMethodInvokeExpression(
                        new CodeMethodReferenceExpression(
                            new CodePropertyReferenceExpression(modelArgument, "Result"),
                            "GetValueOrDefault"),
                            new [] { new CodePrimitiveExpression(0m) }));

Note: after inspection of GetValueOrDefault I found, that it uses HasValue property. So there is no need to call it twice (so compiler will call it twice in case of using ?? operator without optimization. In case of optimization enabled it will simply call GetValueOrDefault). Method contents are given below:

public T GetValueOrDefault(T defaultValue)
{
  if (!this.HasValue)
    return defaultValue;
  else
    return this.value;
}
Akim
  • 8,469
  • 2
  • 31
  • 49
Ilya Ivanov
  • 23,148
  • 4
  • 64
  • 90