cjashwell
cjashwell

Reputation: 629

C# Double type in DataRow to Decimal in Object for XSD serialisation

I need to output XML via serialised objects using XSD. My code achieves this successfully, but there is one issue I need help with.

I have a class called GAD (auto generated using the XSD.exe tool from the XSD) containing a field named total with a type of decimal. In the XSD the element is defined as <xs:element name="Total" type="xs:decimal"/> My final output is going to a third-party validation tool that requires money-style decimals such as 20.00.

My input is a DataTable. This is currently derived from a CSV file (although eventually I will be taking this directly from a database). The DataTable is populated from the CSV using OleDbDataAdapter. Currently the values such as 20.00 are stored in double type columns so the values for whole numbers are 'truncated' to 20.0, for example.

I need to go from a DataRow holding a double value of 20.0 to a decimal object field with a value of 20.00

In trying to achieve this the best I have come up with is converting the double to a string with a format such as this, and then using Math.Round to specify two decimal places when converted back to decimal. It looks like this:

        string dstr = dr["Total"].ToString(); //store the data row value in a string
        double d = Convert.ToDouble(dstr); //store the value in a double
        dstr = d.ToString("0.00"); //convert the double to a formatted string
        decimal NewDec = Math.Round(Convert.ToDecimal(dstr), 2); //decimal value trying to retain decimal places
        GAD.Total = NewDec; //finally store value in my object's field

But it doesn't work. What is stored in GAD.Total is just 20.

I was playing around trying to figure this behaviour out and I don't understand this at all. If I write out the decimal value using the console it displays as 20.00 but hovering over the value shows it is stored as 20: Difference between decimal stored and written out

    class Program
{
    static void Main(string[] args)
    {
        double d = 20.0;

        Console.Write("Cast double as string with format:");
        Console.WriteLine(d.ToString("0.00"));

        string dstr = d.ToString("0.00");
        Console.Write("Cast as string then back to decimal rounded 2 places:");
        Console.WriteLine(Math.Round(Convert.ToDecimal(dstr),2));

        d = 20;
        dstr = d.ToString("0.00");
        Console.WriteLine(Math.Round(Convert.ToDecimal(dstr), 2));

        decimal NewDec = Math.Round(Convert.ToDecimal(dstr), 2);
        Console.Write("Stored in a decimal: ");
        Console.WriteLine(NewDec);

        Console.Read();

    }
}

So, I have two questions:

  1. Why is the value of NewDec in this example stored as 20 but output by console as 20.00?
  2. How can I go from a double stored in a DataRow as 20.0 to a decimal held in an object field as 20.00?

Thank you for your attention and I would be grateful for any help you can offer me.

Upvotes: 0

Views: 3622

Answers (1)

cjashwell
cjashwell

Reputation: 629

I still don't know the answer to question 1 but I have solved question 2.

As per this link http://social.msdn.microsoft.com/Forums/en-US/csharplanguage/thread/d7582772-ab2c-4f05-9ba3-c96728dfbe82 I changed the definition of my class GAD.

   [XmlIgnore]            
   public decimal Total
        {
            get
            {
                return this.totalField;
            }
            set
            {
                this.totalField = value;
            }
        }


        [XmlElement("Total")]
        public string TotalString
        {
            get
            {
                return Total.ToString("F2");
            }
            set
            {
                decimal total = 0;
                if (Decimal.TryParse(value, out total))
                    Total = total;
            }
        }

Now, when I initialise the object field from my data table I can simply use GAD.Total = Convert.ToDecimal(dr["Total"]); and the serialized output in XML always returns the numeric value with two decimal places, like so: <Total>30.00</Total>

Upvotes: 1

Related Questions