ToString的奇数十进制类型行为(IFormatProvider)

时间:2012-12-10 23:12:14

标签: c# iformatprovider

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");

在控制台中:     10.00     10     真

为什么会有所不同?更重要的是,无论变量如何初始化,如何调用ToString()以确保相同的输出?

3 个答案:

答案 0 :(得分:4)

如何使其输出始终如一的问题已得到解答,但这就是为什么它们首先输出不同的原因:

decimal值在内部包含比例和系数的字段。在10M的情况下,编码的值具有10的系数和0的标度:

10M = 10 * 10^0

10.00M的情况下,编码的值的系数为1000,比例为2:

10.00M = 1000 * 10^(-2)

您可以通过检查内存中的值来看到这一点:

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") + " ");
    }
}

输出

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为十六进制为10,0x3E8为十六进制为1000)

C#规范的第2.4.4.3节概述了这种行为:

  

以M或m为后缀的实数是十进制类型。例如,文字1m,1.5m,1e10m和123.456M都是十进制类型。通过获取精确值将此文字转换为十进制值,并在必要时使用银行家舍入(第4.1.7节)舍入到最接近的可表示值。 除非值已四舍五入或值为零(在后一种情况下,符号和比例将为0),否则将保留文字中明显的任何比例。因此,将解析文字2.900m以形成带符号0,系数2900和比例3的小数。

答案 1 :(得分:2)

NumberDecimalDigits属性与"F""N"标准格式字符串一起使用,而不是在没有格式字符串的情况下调用的ToString方法。

您可以使用:

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

答案 2 :(得分:1)

试试这个:

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

输出总是2个十进制的情况。更多例子:

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