为什么长和十进制之间的等于不可交换?

cos*_*sta 12 .net c#

我有这个代码我在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();
Run Code Online (Sandbox Code Playgroud)

它产生这个输出:

    9223372036854775807
    9223372036854775807
    True
    True
    False
    False
    False
    True
Run Code Online (Sandbox Code Playgroud)

注意最后两行:x.Equals(y)为false但y.Equals(x)为true.因此,十进制认为自身等于具有相同值的long,但long不认为自己等于具有相同值的十进制.

这种行为的解释是什么?

更新:

我接受了Lee的回答.

我对此非常好奇并写了这个小程序:

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();
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

然后我在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 
}
Run Code Online (Sandbox Code Playgroud)

您确实可以看到长值转换为十进制.

感谢你们!

Lee*_*Lee 18

发生这种情况是因为

y.Equals(x);
Run Code Online (Sandbox Code Playgroud)

decimal.Equals(decimal)过载被调用,因为有一个隐式转换之间longdecimal.结果,比较返回true.

然而,由于没有来自隐式转换decimallong

x.Equals(y)
Run Code Online (Sandbox Code Playgroud)

long.Equals(object)导致y被装箱的调用和比较返回,false因为它不能被取消装箱.

  • 你正在寻找错误的转换.```不能用`long`表示.因此,从"decimal"到"long"的转换必须是显式的,因为它会导致精度损失.从"long"到"decimal"的转换是隐含的. (2认同)
  • @leppie - 没有比较位模式.选择`Equals(object)`重载,因为没有从`ulong`到`long`的隐式转换.参数是盒装的,`long.Equals(object)`方法必须做的第一件事就是查看参数是否是一个盒装长的比较.由于参数是一个盒装的`ulong`,因此失败了. (2认同)

paq*_*mez 6

隐式转换和显式转换.

来自MSDN:

隐式转换:不需要特殊语法,因为转换是类型安全的,不会丢失任何数据.示例包括从较小到较大整数类型的转换,以及从派生类到基类的转换.

显式转换(强制转换):显式转换需要强制转换运算符.如果信息可能在转换中丢失,或者由于其他原因导致转换失败,则需要进行转换.典型示例包括将数字转换为精度较低或范围较小的类型,以及将基类实例转换为派生类.

long很容易转换为小数,但反之则不然,因此评估失败.