ToString的奇数十进制类型行为(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()以确保相同的输出?

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

您可以使用:

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

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

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为hex,0x3E8为hex为1000)

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

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

试试这个:

 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/