Casting string to double, dot gets removed

While casting from string to double, the dot gets removed, eg. for 0.01 after casting to double it gives 1, or for 3.22 it gives 322.

Below is the Code I used.

In log file I get

Before Usage :- 0.01

After it Parse :- 1

while (reader.Read())
{
    XmlNodeType nType = reader.NodeType;
    if (nType == XmlNodeType.Element && reader.Name == "DepartmentUser")
    {
        UserData user = new UserData();
        while (reader.MoveToNextAttribute())
        {
            if (reader.Name == "UserName")
            {
                user.UserName = Convert.ToString(reader.Value);
            }
            else if (reader.Name == "UserID")
            {
                user.UserGUID = Convert.ToString(reader.Value);
            }
            else if (reader.Name == "UserUsage")
            {
                Logger.TraceLog(LogLevel.Debug, string.Format("Before Usage :- {0}", reader.Value));
                //user.DiskUsage = Convert.ToDouble(reader.Value);
                user.UserUsage = double.Parse(reader.Value);
                Logger.TraceLog(LogLevel.Debug, string.Format("After it Parse :- {0}", user.UserUsage));
            }
        }
    }
}

Is this due to Culture?

Jon Skeet
people
quotationmark

I strongly suspect this is indeed a culture issue - your thread's current culture probably uses . as a grouping separator rather than a decimal separator. In fact, in some cultures your code would just fail with an exception. Here's an example demonstrating the problem:

using System;
using System.Globalization;
using System.Threading;

class Test
{
    static void Main()
    {
        var german = CultureInfo.GetCultureInfo("de-DE");
        var english = CultureInfo.GetCultureInfo("en-GB");
        var text = "1.5";

        Thread.CurrentThread.CurrentCulture = german;
        Console.WriteLine(double.Parse(text) == 1.5); // False

        Thread.CurrentThread.CurrentCulture = english;
        Console.WriteLine(double.Parse(text) == 1.5); // True
    }
}

Given that you're converting the content of XML, I'd use XmlConvert.ToDouble instead. That will "do the right thing" assuming that the XML follows the standard representation (which it appears to here).

In this case that will be equivalent to specifying the invariant culture when calling double.Parse (I believe) but I'd prefer the XmlConvert approach because:

  • It's more "clearly correct" for the context
  • It's a pattern you can apply to other types (e.g. DateTime)

Note that if you can possibly read the whole XML document in using LINQ to XML instead, you're likely to find that simpler - and then you can just cast the attribute to double instead. (XmlReader is a pain in the neck - I'd recommend only using it when you really have to due to document size... even then, you could load subtrees into LINQ to XML types.)

people

See more on this question at Stackoverflow