【发布时间】:2015-01-23 20:54:05
【问题描述】:
我有这段代码在 linqpad 中运行:
long x = long.MaxValue;
decimal y = x;
x.Dump();
y.Dump();
(x == y).Dump();
(y == x).Dump();
Object.Equals(x, y).Dump();
Object.Equals(y, x).Dump();
x.Equals(y).Dump();
y.Equals(x).Dump();
它产生这个输出:
9223372036854775807
9223372036854775807
True
True
False
False
False
True
注意最后两行:x.Equals(y) 为假,但 y.Equals(x) 为真。所以小数认为自己等于具有相同值的长,但长不认为自己等于具有相同值的小数。
这种行为的解释是什么?
更新:
我接受了李的回答。
我对此很好奇,就写了这个小程序:
using System;
namespace TestConversion
{
class Program
{
static void Main(string[] args)
{
long x = long.MaxValue;
decimal y = x;
Console.WriteLine(x);
Console.WriteLine(y);
Console.WriteLine(x == y);
Console.WriteLine(y == x);
Console.WriteLine(Object.Equals(x, y));
Console.WriteLine(Object.Equals(y, x));
Console.WriteLine(x.Equals(y));
Console.WriteLine(y.Equals(x));
Console.ReadKey();
}
}
}
然后我在 IL 中反汇编:
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
.maxstack 2
.locals init (
[0] int64 x,
[1] valuetype [mscorlib]System.Decimal y)
L_0000: nop
L_0001: ldc.i8 9223372036854775807
L_000a: stloc.0
L_000b: ldloc.0
L_000c: call valuetype [mscorlib]System.Decimal [mscorlib]System.Decimal::op_Implicit(int64)
L_0011: stloc.1
L_0012: ldloc.0
L_0013: call void [mscorlib]System.Console::WriteLine(int64)
L_0018: nop
L_0019: ldloc.1
L_001a: call void [mscorlib]System.Console::WriteLine(valuetype [mscorlib]System.Decimal)
L_001f: nop
L_0020: ldloc.0
L_0021: call valuetype [mscorlib]System.Decimal [mscorlib]System.Decimal::op_Implicit(int64)
L_0026: ldloc.1
L_0027: call bool [mscorlib]System.Decimal::op_Equality(valuetype [mscorlib]System.Decimal, valuetype [mscorlib]System.Decimal)
L_002c: call void [mscorlib]System.Console::WriteLine(bool)
L_0031: nop
L_0032: ldloc.1
L_0033: ldloc.0
L_0034: call valuetype [mscorlib]System.Decimal [mscorlib]System.Decimal::op_Implicit(int64)
L_0039: call bool [mscorlib]System.Decimal::op_Equality(valuetype [mscorlib]System.Decimal, valuetype [mscorlib]System.Decimal)
L_003e: call void [mscorlib]System.Console::WriteLine(bool)
L_0043: nop
L_0044: ldloc.0
L_0045: box int64
L_004a: ldloc.1
L_004b: box [mscorlib]System.Decimal
L_0050: call bool [mscorlib]System.Object::Equals(object, object)
L_0055: call void [mscorlib]System.Console::WriteLine(bool)
L_005a: nop
L_005b: ldloc.1
L_005c: box [mscorlib]System.Decimal
L_0061: ldloc.0
L_0062: box int64
L_0067: call bool [mscorlib]System.Object::Equals(object, object)
L_006c: call void [mscorlib]System.Console::WriteLine(bool)
L_0071: nop
L_0072: ldloca.s x
L_0074: ldloc.1
L_0075: box [mscorlib]System.Decimal
L_007a: call instance bool [mscorlib]System.Int64::Equals(object)
L_007f: call void [mscorlib]System.Console::WriteLine(bool)
L_0084: nop
L_0085: ldloca.s y
L_0087: ldloc.0
L_0088: call valuetype [mscorlib]System.Decimal [mscorlib]System.Decimal::op_Implicit(int64)
L_008d: call instance bool [mscorlib]System.Decimal::Equals(valuetype [mscorlib]System.Decimal)
L_0092: call void [mscorlib]System.Console::WriteLine(bool)
L_0097: nop
L_0098: call valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey()
L_009d: pop
L_009e: ret
}
您确实可以看到 long 值转换为十进制。
谢谢你们!
【问题讨论】:
-
fyi,将小数点转换回长的作品:
x.Equals((long)y).Dump(); -
虽然这并不能完全解释这种行为,但您可能想看看这个:stackoverflow.com/questions/485175/…
-
@leppie:在实际程序中,我们不会比较它们。我们通过一些调试发现了这一点,我发现它很奇怪 - 因此我的帖子。
-
@costa 考虑更新标题以明确讨论长/小数比较...
-
@costa 你还在问 Equals 是否应该是交流的吗?如果是这样,是的,Equals 应该是交流性和传递性的。但这只是一个指导方针。我以前有理由自己打破这条准则。但是在这种情况下,关于长小数比较,听起来确实像 MS 搞砸了。 Equals 应该检查值是否相等。另请参阅msdn.microsoft.com/en-US/library/ms173147(v=vs.80).aspx,其中明确指出 Equals 的实现应保证 x.Equals(y) 和 y.Equals(x) 返回相同的值。