9

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

It's a client-side filtered textbox (a subclass of TextBox with included javascript and some server side logic for setting/getting the value)

Here is the getter & the setter from that 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 that I'm seeing is that the output from this statement:

decimal Amount = uxAmount.Value ?? 0M;

I am seeing Amount being set to "0" when uxAmount.Value returns 10000.

This worked as I expected (excuse the change in casing):

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

I have also seen this behaviour (recently) when calling a UDF function defined on a Linq2Sql data context along with the null coalescing operator, that is I knew my UDF call returned the expected value but I was getting the RHS value instead.

Further confusing me, if I evaluate uxAmount.Value in the watch, I get 10000 of type Nullable<decimal>.

Here are some expressions I've 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 like the last call is always 0, but the value of uxAmount.Value (which is parsed out of .Text as per above getter/setter using a TryParse is stable. I'm stopped at a breakpoint and there's no other threads that could manipulate this value.

Note the use of the M suffix to force the constant to decimal as it was integer and I suspected a type conversion issue.

Any ideas?

The value of both the LHS and RHS appear to be stable and 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

agrath
  • 901
  • 1
  • 11
  • 25
  • CurrencyTextBox (a subclass of TextBox) – agrath Aug 14 '12 at 21:09
  • 1
    It's a nullable decimal [decimal?] - see the getter/setter definition at the top of the question – agrath Aug 14 '12 at 21:13
  • 1
    Are you sure the debugger dsiplays this correctly to you? Have you tried stepping some lines further down to make sure you have the updated value of `amount3`? Because when `XXX` is a nullable decimal, then `XXX ?? 0M` will be a (non-nullable) decimal that will have the value of `XXX` if that is non-null, and the value zero otherwise. – Jeppe Stig Nielsen Aug 14 '12 at 21:18
  • I can't really reproduce this, possibly an issue with _when_ Text is updated. Or indeed a debugger artifact. – H H Aug 14 '12 at 21:21
  • Hovering over uxAmount.Value shows 10000 as well as in the watch, however the result of the expression seems to always be 0 except when I reevaluate it further down, I will post a couple of screenshots in a sec – agrath Aug 14 '12 at 21:25
  • Curious, what are your C# and .NET versions? OS bitness? – Vlad Aug 14 '12 at 21:27
  • Also, can you move out your property code in a standalone console application and try to reproduce it there? – Vlad Aug 14 '12 at 21:30
  • @Vlad The project is .net4 and using vs2010 so is that c# 4 as well? – agrath Aug 14 '12 at 21:32
  • @JeppeStigNielsen if I step a few more lines, in my screengrabs above, amount3 updates to 10000 as I'd expect.. BUT that causes very strange bugs in my project as the value is not 10000 at the time I'd expect - or is this simply a debugger issue now? – agrath Aug 14 '12 at 21:34
  • 2
    I'm sure it's just an issue with the debugger. Sometimes you have to step a little further. Maybe the translated code (IL) has some optimizations that confuse the debugger (or what would I know). But I'm sure that without the debugger, the value will be updated exactly when you expect it. – Jeppe Stig Nielsen Aug 14 '12 at 21:37
  • My guess is that you're using a Release build and things are getting reordered. Does this problem happen with a Debug build? – Gabe Aug 14 '12 at 21:38
  • Just confirmed by debugging in vs2012, the value debugs consistently there, so I guess vs2010 debugger is the correct answer here – agrath Aug 14 '12 at 21:39
  • @JeppeStigNielsen please post an answer regarding the debugger showing the wrong value and stepping more resolves it so I can accept it for you – agrath Aug 14 '12 at 21:42

2 Answers2

1

Take a look at this similar question

using coalescing null operator on nullable types changes implicit type

why not just do

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

This isn't the right answer to the original posters problems given recent edits and comments.

Community
  • 1
  • 1
Michael Christensen
  • 1,768
  • 1
  • 13
  • 11
1

(This answer was constructed from my comments above.)

Are you sure the debugger dsiplays this correctly to you? Have you tried stepping some lines further down to make sure you have the updated value of amount3?

I'm sure it's just an issue with the debugger. Sometimes you have to step a little further. Maybe the translated code (IL) has some optimizations that confuse the debugger (or what would I know). But without the debugger, the value will be updated exactly when you expect it.

I've seen other experienced developers being confused by similar situations, so I know the debugger sometimes is "one line of code" behind when looking at an assignment to a local variable. Maybe someone can find a link discussing that?

Jeppe Stig Nielsen
  • 60,409
  • 11
  • 110
  • 181