Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 为什么long和decimal之间的Equals是不可交换的?_C#_.net - Fatal编程技术网

C# 为什么long和decimal之间的Equals是不可交换的?

C# 为什么long和decimal之间的Equals是不可交换的?,c#,.net,C#,.net,我在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();

我在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值被转换为decimal


谢谢你们

您正在比较对象引用和值。当然,这些引用并不相同——除了在第2行中显式设置的引用。但是,这些值是


C#自动为您管理指针(例如“引用内存”)。您正在访问一个从语法上看不明显的层。这就是C#隐式与显式转换的本质

发件人:

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

显式转换(强制转换):显式转换需要强制转换 操作人员当信息可能丢失时,需要强制转换 转换,或者在其他系统的转换可能无法成功时 原因。典型示例包括将数值转换为 具有较低的精度或较小的范围,以及基类的转换 一个派生类的实例


long可以很容易地转换为十进制,但反之则不正确,因此计算失败。

这是因为

y.Equals(x);
正在调用
decimal.Equals(decimal)
重载,因为
long
decimal
之间存在一个中间值。结果,比较返回true

但是,由于没有从
decimal
long

x.Equals(y)

调用
long.Equals(object)
,这会导致
y
被装箱,并且比较返回
false
,因为它不能被解装箱为long。

fyi,将小数点转换回long works:
x.Equals((long)y).Dump()虽然这并不能确切解释这种行为,但您可能想看看这个:@leppie:在实际的程序中,我们不会比较它们。我们通过做一些调试发现了这一点,我发现它很奇怪——因此我的帖子。“科斯塔考虑更新标题来明确地讨论长/小数比较……”科斯塔,你还在问平等是否应该交流?如果是这样,yesequals应该是交际性和及物性的。但这只是一个指导方针。以前我自己也有理由违反这一准则。但在这种情况下,关于长和十进制的比较,这听起来确实像是MS搞砸了。Equals应该检查值是否相等。另外,请参阅其中明确说明Equals的实现应保证x.Equals(y)和y.Equals(x)返回相同的值。如果指针不是相同的对象,它们都是值类型。Equals将失败,因为对象确实不相等。这里不叫Object.equals。这个答案加上来自其他答案的链接-给出了完整的解释。这个答案很奇怪,但不知何故还是感觉正确。。。你是说虽然decimal知道long,但long不知道decimal(在转换方面)?你看到的是错误的转换<代码>1.1
不能用
表示。因此,从
decimal
long
的转换必须是明确的,因为这将导致精度损失。从
long
decimal
的转换是隐式的。原因相同。因为没有从
ulong
long
的隐式转换。为什么会这样?因为有些值可以在
ulong
中表示,但不能在
long
@leppie中表示,所以不会比较位模式。选择
Equals(object)
重载,因为没有从
ulong
long
的隐式转换。参数是装箱的,
long.Equals(object)
方法必须做的第一件事是查看参数是否是装箱的long来进行比较。此操作失败,因为参数是装箱的
ulong