Understanding the zero coalescence operator (??)

I have a custom WebControl that implements getter / setter .Value returning a Nullable <decimal>

This is a text field with a filter on the client side (a subclass of TextBox with javascript enabled and some logic on the server side to set / get the value)

Here is the getter and setter from this control:

 public decimal? Value { get { decimal amount = 0; if (!decimal.TryParse(this.Text, NumberStyles.Currency, null, out amount)) { return null; } else { return amount; } } set { if (!value.HasValue) { this.Text = ""; } else { this.Text = string.Format("${0:#,##0.00}", value); } } } 

The problem I see is that the conclusion from this statement is:

 decimal Amount = uxAmount.Value ?? 0M; 

I see that Amount is set to "0" when uxAmount.Value returns 10000.

This worked as I expected (sorry for changing the casing):

 decimal? _Amount = uxAmount.Value; decimal amount = _Amount ?? 0; 

I also saw this behavior (recently) when calling the UDF function defined in the Linq2Sql data context, along with the zero coalescence operator, that is, I knew that my UDF call returned the expected value, but instead I got the RHS value.

Further it confuses me if I evaluate uxAmount.Value in hours, I get 10000 of type Nullable<decimal> .

Here are some expressions I tried:

 decimal? _Amount = uxAmount.Value; //10000 decimal amount = _Amount ?? 0; //10000 decimal amount2 = _Amount ?? 0M; //10000 decimal Amount = uxAmount.Value ?? 0M; //0 

Then I added this expression, following the above 4

 decimal amount3 = (uxTaxAmount.Value) ?? 0M; 

Now

 decimal Amount = uxAmount.Value ?? 0M; //10000 decimal amount3 = (uxAmount.Value) ?? 0M; //0 

It seems that the last call is always 0, but the value of uxAmount.Value (which is parsed from .Text according to the getter / setter above with TryParse is stable. I am stopped at the breakpoint and there are no other threads that could manipulate this value.

Note the use of the M suffix to force the constant to be decimal, since it was an integer, and I suspected a type conversion problem.

Any ideas?

The value of both LHS and RHS looks stable and well-known.

- edit-- some screengrabs from VS2010

Stepping through the code showing the value of amount3

Watch dialog and some more detail about state of variables

+8
c # nullable null-coalescing-operator
source share
2 answers

(This answer was built from my comments above.)

Are you sure the dsiplays debugger is right for you? Have you tried a few more steps to make sure you have an updated amount3 value?

I am sure this is just a problem with the debugger. Sometimes you need to step a little further. Perhaps the translated code (IL) has some optimizations that confuse the debugger (or what I know). But without a debugger, the value will be accurately updated when you expect it.

I saw other experienced developers confused by similar situations, so I know that the debugger is sometimes a β€œone line of code” when it looks at the purpose of a local variable. Maybe someone can find a link discussing this?

0
source share

Take a look at this similar question

using the coalescing null operator in types with null type changes the implicit type

why not just do

 decimal amount = uxTaxAmount.Value.HasValue ? uxTaxAmount.Value.Value : 0M 

This is the wrong answer to the original poster issues, given the recent changes and comments.

+1
source share

All Articles