Understanding the null coalescing operator (??) - c#

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

(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?

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.

Related

C# ignore empty textboxes

I have ha a WinForms app with some textboxes.
At the moment the app is simple and i only want to test how it will work.
It will get mutch more complex in the future.
What i tried to do create a rule to ignore empty textboxes or if empty use the value 0.
The code i have is this one:
decimal ata;
decimal a1;
decimal a2;
decimal a3;
decimal a4;
decimal a5;
decimal j = 0;
a1 = decimal.TryParse(textBox1.Text, out j);
a2 = decimal.Parse(textBox2.Text);
a3 = decimal.Parse(textBox4.Text);
a4 = decimal.Parse(textBox10.Text);
a5 = decimal.Parse(textBox24.Text);
ata = a1 + a2 + a3 + a4 + a5;
resposta.Text = ata.ToString();
i get an error "Cannot implicitly convert type 'bool' to 'decimal'
in the line:
a1 = decimal.TryParse(textBox1.Text, out j);
Can anyone help me with this problem.
Thanks in advance,
Use decimal.TryParse(textBox1.Text, out j); instead of a1 = decimal.TryParse(textBox1.Text, out j);. Your value is returned in j
You declared
decimal a1;
Then you tried:
a1 = decimal.TryParse(textBox1.Text, out j);
decimal.TryParse returns a bool not a decimal
j
Is taking the parsed value
The TryParse method returns a bool value to indicate whether conversion succeeded or not. The real value is returned in the second parameter (out parameter).
You could try:
if (Decimal.TryParse(textBox1.Text, out j))
a1 = j;
This only sets a1 if parsing was successful. Otherwise a1 keeps its previous value.
The way you want to use the TryParse() method is like so
decimal a1 = 0;
bool parsed = decimal.TryParse(textBox1.Text, out a1);
if(parsed)
{
//your arithmetic
}
else
{
//throw error
}
The error is because TryParse() returns a boolean, not a decimal. You need to write explicit if statements to test if the textboxes are empty. You should consider wrapping this in a method.
You are trying to assign a bool value to a decimal variable that's why getting this error.
Decimal.TryParse() will return bool value, Please take a look here you can use this value to check parsing is successful or not.
You will get result in your out parameter i.e j.
the return value TryParse is a bool. It indicates whether the conversion was successful or not. Usually you would use it like this:
decimal j;
if (decimal.TryParse(textBox1.Text, out j))
{
// here the conversion worked and it is save to use j
}
You check whether it was successful and in this case you can use the value of the converted variable, otherwise it will remain null.
Here is the documentation
In respect to the value that is passed via the out keyword the documentation says: (s is equivalent to textBox1.Text and result is equivalent to j)
When this method returns, result contains the Decimal number that is equivalent to the numeric value contained in s, if the conversion succeeded, or is zero if the conversion failed. The conversion fails if the s parameter is null or String.Empty, is not a number in a valid format, or represents a number less than MinValue or greater than MaxValue. This parameter is passed uninitialized; any value originally supplied in result will be overwritten.
One of the nice things of object oriented programming is reusability of code in similar situations.
You mentioned you are going to use some kind of "nullable decimal text boxes" a lot of times. Why not create a class for it? You'll only have to create the class once, and everyone who needs your nullable decimal text box (especially you with all your text boxes) can reuse this one code.
Bonus: if you ever need to change the behaviour of this kind of text boxes, for instance get a yellow background when empty, all your special text boxes instantaneously behave the same.
To make it possible to ignore empty text boxes you need a property IsEmpty
Property Value returns the Value of the text box as a decimal or 0M if IsEmpty
What do you want to return if not empty but text is not a decimal?
public class MyNullableTextBox : TextBox
{
public bool IsEmpty {get{return String.IsNullOrEmpty(base.Text);} }
public decimal Value
{
get
{
if (this.IsEmpty)
return 0M;
else
{
decimal parsedValue;
bool parsed = Decimal.TryParse(base.Text, out parsedValue);
if (!parsed)
// decide what you want in this case
else
return parsedValue;
}
}
}
}
The nice thing is, that once you've added this (as a reference) to your solution, it can be found in the Toolbox and used in your forms designer as if it was a regular text box

How can I deal with this double.NaN

I have the a Convert.ToDecimal() which occasionally throws an exception with the message
Value was either too large or too small for a Decimal
, because the call to DataContainer.GetValue(ColKeyId, index) returns double.NaN.
if (Convert.ToDecimal(DataContainer.GetValue(ColKeyId, index)) != Convert.ToDecimal(newValueToSet))
{
DataContainer.SetValue(ColKeyId, index, newValueToSet);
}
I cannot change the API implementation call of the GetValue().
What would be the best approach to deal with the conversion to decimal of a NaN double?
Okay, so it sounds like you just need to detect whether or not it's a NaN value:
double value = DataContainer.GetValue(ColKeyId, index);
if (double.IsNaN(value) || double.IsInfinity(value) ||
(decimal) value != (decimal) newValueToSet)
{
DataContainer.SetValue(ColKeyId, index, newValueToSet);
}
To be honest, it's not clear why you're converting from double to decimal at all, but this code at least shows how you can detect NaN/infinite values. Note that I've changed the calls to Convert.ToDecimal to simple casts to make the code simpler - but you could use Convert.ToDecimal if you want, of course..
Decimal.TryParse
So then you will know if it converted or not and if not assigne a defasult value or branch off down some other avenue.
HTH
You can check if the value is double.NaN before setting:
if (!Double.IsNaN(DataContainer.GetValue(ColKeyId, index)))
{
if (Convert.ToDecimal(DataContainer.GetValue(ColKeyId, index)) != Convert.ToDecimal(newValueToSet))
{
DataContainer.SetValue(ColKeyId, index, newValueToSet);
}
}

Nullable double NaN comparison in C#

I have 2 nullable doubles, an expected value and an actual value (let's call them value and valueExpected). A percentage is found using 100 * (value / valueExpected). However, if valueExpected is zero, it returns NaN. Everything good so far.
Now, what do I do if I need to check the value, to see if it is NaN? Normally one could use:
if (!Double.IsNaN(myDouble))
But this doesn't work with nullable values (IsNaN only works with non-nullable variables). I have changed my code to do the check (valueExpected == 0), but I'm still curious - is there any way to check for a nullable NaN?
Edit: When I say the code doesn't work, I mean it won't compile. Testing for null first doesn't work.
With all Nullable<T> instances, you first check the bool HasValue property, and then you can access the T Value property.
double? d = 0.0; // Shorthand for Nullable<double>
if (d.HasValue && !Double.IsNaN(d.Value)) {
double val = d.Value;
// val is a non-null, non-NaN double.
}
You can also use
if (!Double.IsNaN(myDouble ?? 0.0))
The value in the inner-most parenthesis is either the myDouble (with its Nullable<> wrapping removed) if that is non-null, or just 0.0 if myDouble is null. Se ?? Operator (C#).
I had the same issue and I solved it with casting the double? with double
double.IsNaN((double)myDouble)
this will return true if NaN and false if not
With C# 7.0 Pattern matching combined null + NaN check check can be written like this:
double? d = whatever;
if(d is double val && double.IsNaN(val))
Console.WriteLine(val);
The advantage is local scoped variable val at hand, which is not null, nor double.NaN and can even be used outside of if.
With pattern matching in newer Roslyn C# versions, double.NaN is a valid pattern which tests using IsNaN (that is it works differently than Equals() where NaN is never equal to NaN as specified by IEEE floating point standard).
Therefore you can now do this:
double? myDouble = something;
if (myDouble is double and not double.NaN)
Console.WriteLine("A number");
For testing NaN this can even be shortened like this:
double? myDouble = something;
if (myDouble is double.NaN)
Console.WriteLine("Not a number and not NULL");

How to check for valid value before converting Decimal

I assume this will blow up if total is null (I don't recall if decimals are initalized to null at the beginning or zero)
public int SomePropertyName
{
get { return Convert.ToInt32(Decimal.Round(total)); }
}
So should I check for null or > 0 ?
Decimal is a value type - there's no such value as "null" for a decimal.
However, it's perfectly possible for a decimal to be out of range for an int. You might want:
decimal rounded = decimal.Round(total);
if (rounded < int.MinValue || rounded > int.MaxValue)
{
// Do whatever you ought to here (it will depend on your application)
}
return (int) rounded;
I'm somewhat confused as to why you're using Convert.ToInt32 at all though, given that your property is declared to return a decimal. What's the bigger picture here? What are you trying to achieve?
Decimal is a value type and can not be null.
If you need to know if it had been initialized, you should probably use a nullable decimal:
Decimal? total = null;
public int SomePropertyName
{
get
{
if (total.HasValue) Convert.ToInt32(Decimal.Round(total.Value));
return 0; // or whatever
}
}
Decimals are value types, and so cannot be null.
So no need to check there..
As others have said, Decimal is a value type and cannot be null. However, if converting from a string then Decimal.TryParse is your friend...
System.Decimal is a value type, so it cannot be null. Second thing, the method's return value is decimal, so why would you want to convert to a Int32?

LinqToXML, breaking when Node doesn't exist. How do I check for existence?

var doc = XDocument.Parse(inputXML);
this bombs out when "amount" node is not present. How can I check for existence prior to evaluating?
decimal amt;
var amount = doc.Descendants("amount").SingleOrDefault().Value;
bool amountValid = decimal.TryParse(amount, out amt);
I need to make sure "amount" is available prior to evaluating.
Can anyone help?
Thanks All,
~ck in San Diego
XElement provides explicit casts for most value types, including Nullable<Decimal>:
var amt = (decimal?)doc.Descendants("amount").SingleOrDefault();
From there you can check if amt is null or use its HasValue property.
Update: It's worth pointing out that the cast will throw a FormatException if the value is not a Decimal. If you still want to use TryParse, you can keep the code simple with a string cast:
decimal amt;
var amount = (string)doc.Descendants("amount").SingleOrDefault();
bool amountValid = decimal.TryParse(amount, out amt);
Internally, the string cast is implemented like Ben's sample, returning either null or element.Value.
Try this:
var amountElement = doc.Descendants("amount").SingleOrDefault();
if (amountElement != null)
{
decimal amt;
bool amountValid = decimal.TryParse(amountElement.Value, out amt);
// other code
}

Categories

Resources