如果我们将填充声明为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
}
}
答案 0 :(得分:15)
编译器“知道”将值“0”添加到“不应该”更改值 - 因此它会优化此值。现在可以说,鉴于十进制加法的性质,这是一个无效的优化,但如果你看一下生成的代码,你会发现mymoney
的计算不涉及添加。
我不认为我会尝试使用添加0.00米作为确保特定比例的方法,说实话。您可以创建自己的代码以使用decimal.GetBits
和the constructor performing the reverse operation来强制执行扩展 - 但我认为它不会非常好。
你肯定需要这个“两位小数”形式作为中间值,还是仅用于演示?如果是后者,我会查看格式字符串。
答案 1 :(得分:4)
作为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,然后加载可执行文件并双击要查看的方法。
答案 2 :(得分:2)
balance + ConstPadding == balance
因为ConstPadding为零!
你应该 -
Console.WriteLine(yourmoney.ToString("0.00")); //1.20
答案 3 :(得分:1)
使用常量填充的求和运算完全被排除在MSIL之外,但它存在于非常量字段中。 遗憾的是,我无法找到任何对FCallAddSub函数的引用,但那是“优化”调用的那个。
答案 4 :(得分:1)
如果我没有弄错,编译器没有使用常数十进制进行加法,因为它是零。
很快会发布证据。
Jon Skeet在上面的答案中证明了这一点。