Domanda

var numberFormat = new NumberFormatInfo();
numberFormat.NumberDecimalSeparator = ".";
numberFormat.NumberDecimalDigits = 2;

decimal a = 10.00M;
decimal b = 10M;

Console.WriteLine(a.ToString(numberFormat));
Console.WriteLine(b.ToString(numberFormat));
Console.WriteLine(a == b ? "True": "False");

In console: 10.00 10 True

Why is it different? More important, how do I call ToString() to ensure same output no matter how a variable is initialized?

È stato utile?

Soluzione 2

The NumberDecimalDigits property is used with the "F" and "N" standard format strings, not the ToString method called without a format string.

You can use:

Console.WriteLine(a.ToString("N", numberFormat));

Altri suggerimenti

The question of how to make it output consistently has been answered, but here is why they output differently in the first place:

A decimal value contains, internally, fields for a scale and a coefficient. In the case of 10M, the value encoded has a coefficient of 10 and a scale of 0:

10M = 10 * 10^0

In the case of 10.00M, the value encoded has a coefficient of 1000 and a scale of 2:

10.00M = 1000 * 10^(-2)

You can sort of see this by inspecting the values in-memory:

unsafe
{
    fixed (decimal* array = new decimal[2])
    {
        array[0] = 10M;
        array[1] = 10.00M;
        byte* ptr = (byte*)array;

        Console.Write("10M:    ");
        for (int i = 0; i < 16; i++)
            Console.Write(ptr[i].ToString("X2") + " ");

        Console.WriteLine("");

        Console.Write("10.00M: ");
        for (int i = 16; i < 32; i++)
            Console.Write(ptr[i].ToString("X2") + " ");
    }
}

Outputs

10M:    00 00 00 00 00 00 00 00 0A 00 00 00 00 00 00 00
10.00M: 00 00 02 00 00 00 00 00 E8 03 00 00 00 00 00 00

(0xA is 10 in hex, and 0x3E8 is 1000 in hex)

This behaviour is outlined in section 2.4.4.3 of the C# spec:

A real literal suffixed by M or m is of type decimal. For example, the literals 1m, 1.5m, 1e10m, and 123.456M are all of type decimal. This literal is converted to a decimal value by taking the exact value, and, if necessary, rounding to the nearest representable value using banker's rounding (§4.1.7). Any scale apparent in the literal is preserved unless the value is rounded or the value is zero (in which latter case the sign and scale will be 0). Hence, the literal 2.900m will be parsed to form the decimal with sign 0, coefficient 2900, and scale 3.

Try this:

Console.WriteLine(String.Format("{0:0.00}", a)); 
Console.WriteLine(String.Format("{0:0.00}", b)); 

The output will have always 2 decimal cases. More examples here:

http://www.csharp-examples.net/string-format-double/

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top