У меня есть этот код я бегу в 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.equals (х) правда. Таким образом, десятичное число считается равным длине с тем же значением, но long не считает себя равным десятичной, имеющей одно и то же значение.
В чем причина этого поведения?
Обновление:
Я принял ответ Ли.
мне было очень интересно, об этом и написал эту маленькую программу:
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
}
Вы можете увидеть на самом деле, что долгое значение преобразуется в десятичную.
Спасибо, ребята!
fyi, отбрасывая десятичную дробь на длинные работы: 'x.Equals ((long) y) .Dump();' – DLeh
Хотя это не совсем объясняет это поведение, вы можете взглянуть на это: http://stackoverflow.com/questions/485175/is-it-safe-to-check-floating-point-values-for-equality-to-0-in-c-net/485210#485210 – seN
@leppie : В реальной программе мы их не сравниваем. Мы обнаружили это, выполнив некоторую отладку, и мне показалось странным - отсюда и мой пост. – costa