TryParse failing with negative numbers

21.3k views Asked by At

I'm having a problem getting TryParse to work correctly for me. I have a list of values that I am almost assured are valid (as they come from another component in our system) but I would like to make sure there is proper error handling in place.

Here is an example list of my values:

20.00
20.00
-150.00

And here is the method I originally wrote:

 private decimal CalculateValue(IEnumerable<XElement> summaryValues)
        {
            decimal totalValue = 0;

            foreach (XElement xElement in summaryValues)
            {
                decimal successful;
                Decimal.TryParse(xElement.Value, out successful);
                if (successful > 0)
                    totalValue += Decimal.Parse(xElement.Value);
            }
            return totalValue;
        }

The variable 'successful' was returning false for -150.00, so I added NumberStyles:

private decimal CalculateValue(IEnumerable<XElement> summaryValues)
        {
            decimal totalValue = 0;

            foreach (XElement xElement in summaryValues)
            {
                decimal successful;
                Decimal.TryParse(xElement.Value, NumberStyles.AllowLeadingSign, null, out successful);
                if (successful > 0)
                    totalValue += Decimal.Parse(xElement.Value, NumberStyles.AllowLeadingSign);
            }
            return totalValue;
        }

However, now that I have the NumberStyles in there, none of the numbers will parse! I feel good about having IFormatProvider set to null as this is all within our system. Does anyone see what I may be doing wrong?

6

There are 6 answers

0
Joel Mueller On BEST ANSWER

The other answers have got the right idea with regard to the proper way to use Decimal.TryParse. However, if I were writing the method in question, I'd use LINQ to work with LINQ-to-XML objects:

private decimal CalculateValue(IEnumerable<XElement> summaryValues)
{
    return summaryValues
        .Sum(el =>
             {
                 decimal value;
                 if (Decimal.TryParse(el.Value, out value))
                     return value;
                 return 0M;
             });
}

This version works the exact same way, but it uses the Enumerable.Sum method to calculate the total. All I have to supply is an inline function that extracts decimal values from an XElement.

2
Chris Shain On

This is not how you are supposed to use TryParse.

TryParse returns a boolean (true/false), so your code above should be:

private decimal CalculateValue(IEnumerable<XElement> summaryValues)
        {
            decimal totalValue = 0;

            foreach (XElement xElement in summaryValues)
            {
                decimal valueReturned;
                bool successful = Decimal.TryParse(xElement.Value, out valueReturned);
                if (successful)
                    totalValue += valueReturned;
            }
            return totalValue;
        }

or more succinctly,

private decimal CalculateValue(IEnumerable<XElement> summaryValues)
        {
            decimal totalValue = 0;

            foreach (XElement xElement in summaryValues)
            {
                decimal valueReturned;
                if (Decimal.TryParse(xElement.Value, out valueReturned))
                    totalValue += valueReturned;
            }
            return totalValue;
        }
0
Brad Christie On

your successful is going to be negative for a negative value being parsed. your if (successful > 0) is what's tripping you up.

If they are almost positively going to be valid values, try using Convert.ToDecimal:

decimal val = Convert.ToDecimal(xElement.Value);

Otherwise, change your logic a bit to be more like:

decimal val;
if (Decimal.TryParse(xElement.Value, out val)){
  // valid number
}
0
ncoder83 On

I would suggest you to tell XElement which node value it should look for as in:

XElement.Element("nodename").Value

Instead of XElement.Value. at least that is what I would do :)

1
McAden On

Others are explaining how to do it right, but not really explaining what you're doing wrong.

Where you're using "successful" above isn't the success value, it's the actual number that is being parsed. So if you're parsing "-150.00" of course successful will be negative. The out value of TryParse is the actual parsed value and the boolean indicating whether the process was successful or not is the returned value. Using what you have to help understand would be something like:

string inputValue = "-150.00";
decimal numericValue;
bool isSucessful = Decimal.TryParse(inputValue , out numericValue);

In this case, isSuccessful will be TRUE, numericValue will be -150. When you're using user-provided values instead of the hardcoded one I used above you'll want to check:

if(isSuccessful)
{
    // Do something with numericValue since we know it to be a valid decimal
}
else
{
    // Inform User, throw exception, etc... as appropriate, Don't use numericValue because we know it's wrong.
}
1
Slate On

Came in from Google. Answer for me was the incoming culture was wrong - specifically in an incoming JSON file.

Use

totalValue += decimal.Parse(xElement.Value, NumberStyles.Any, CultureInfo.InvariantCulture);

or

bool successful = decimal.TryParse(xElement.Value, NumberStyles.Any, CultureInfo.InvariantCulture, out value);