C#中“decimal”类型的有趣行为

如果我们将填充声明为const十进制,则填充不起作用。

mymoney = 1.2,你的钱= 1.20,这个行为怎么解释?

class Program { static void Main(string[] args) { decimal balance = 1.2m; const decimal ConstPadding = 0.00m; decimal padding = 0.00m; decimal mymoney = decimal.Round(balance + ConstPadding, 2); decimal yourmoney = decimal.Round(balance + padding, 2); Console.WriteLine(mymoney); // 1.2 Console.WriteLine(yourmoney); //1.20 } } 

作为Jon的答案的伴奏,下面是您的代码生成的IL。 正如他所提到的那样,mymoney从未被添加过。

 .method private hidebysig static void Main(string[] args) cil managed { .entrypoint // Code size 61 (0x3d) .maxstack 6 .locals init ([0] valuetype [mscorlib]System.Decimal balance, [1] valuetype [mscorlib]System.Decimal padding, [2] valuetype [mscorlib]System.Decimal mymoney, [3] valuetype [mscorlib]System.Decimal yourmoney) IL_0000: nop IL_0001: ldc.i4.s 12 IL_0003: ldc.i4.0 IL_0004: ldc.i4.0 IL_0005: ldc.i4.0 IL_0006: ldc.i4.1 IL_0007: newobj instance void [mscorlib]System.Decimal::.ctor(int32, int32, int32, bool, uint8) IL_000c: stloc.0 IL_000d: ldc.i4.0 IL_000e: ldc.i4.0 IL_000f: ldc.i4.0 IL_0010: ldc.i4.0 IL_0011: ldc.i4.2 IL_0012: newobj instance void [mscorlib]System.Decimal::.ctor(int32, int32, int32, bool, uint8) IL_0017: stloc.1 IL_0018: ldloc.0 IL_0019: ldc.i4.2 IL_001a: call valuetype [mscorlib]System.Decimal [mscorlib]System.Decimal::Round(valuetype [mscorlib]System.Decimal, int32) IL_001f: stloc.2 IL_0020: ldloc.0 IL_0021: ldloc.1 IL_0022: call valuetype [mscorlib]System.Decimal [mscorlib]System.Decimal::op_Addition(valuetype [mscorlib]System.Decimal, valuetype [mscorlib]System.Decimal) IL_0027: ldc.i4.2 IL_0028: call valuetype [mscorlib]System.Decimal [mscorlib]System.Decimal::Round(valuetype [mscorlib]System.Decimal, int32) IL_002d: stloc.3 IL_002e: ldloc.2 IL_002f: call void [mscorlib]System.Console::WriteLine(valuetype [mscorlib]System.Decimal) IL_0034: nop IL_0035: ldloc.3 IL_0036: call void [mscorlib]System.Console::WriteLine(valuetype [mscorlib]System.Decimal) IL_003b: nop IL_003c: ret } // end of method Program::Main 

要生成IL(即如果您希望将来看一下),只需从VS命令提示符运行ILDASM,然后加载可执行文件并双击要查看的方法。

编译器“知道”将值“0”添加到“不应该”更改值 – 因此它会优化此值。 现在可以说,鉴于十进制加法的性质,这是一个无效的优化,但是如果你看一下生成的代码,你会发现mymoney的计算不涉及添加。

老实说,我认为我不会尝试使用添加0.00米作为确保特定规模的方法。 您可以创建自己的代码来强制执行扩展,使用decimal.GetBits和执行反向操作的构造函数 – 但我不认为它会非常好。

你肯定需要这个“两位小数”forms作为中间值,还是仅用于演示? 如果是后者,我会查看格式字符串。

 balance + ConstPadding == balance 

因为ConstPadding是零!

你应该 –

 Console.WriteLine(yourmoney.ToString("0.00")); //1.20 

具有常量填充的求和操作完全被排除在MSIL之外,但它存在于非常量字段中。 遗憾的是,我无法找到任何对FCallAddSub函数的引用,但那是“优化”调用的那个。

如果我没有弄错,编译器不会使用常数十进制进行加法,因为它是零。

很快会发布证据。

Jon Skeet的certificate在上面回答。