为什么整数零不等于长零?

pau*_*s_l 20 .net c#

我在C#中发现的一段奇怪的代码(对于使用.NET的其他CLI语言也应如此structs).

using System;

public class Program
{
    public static void Main(string[] args)
    {
    int a;
    long b;

    a = 0;
    b = 0;

    Console.WriteLine(a.Equals(b)); // False
    Console.WriteLine(a.Equals(0L)); // False
    Console.WriteLine(a.Equals((long)0)); // False
    Console.WriteLine(a.Equals(0)); // True
    Console.WriteLine(a.Equals(a)); // True
    Console.WriteLine(a == b); // True
    Console.WriteLine(a == 0L); // True

    Console.WriteLine();

    Console.WriteLine(b.Equals(a)); // True
    Console.WriteLine(b.Equals(0)); // True
    Console.WriteLine(b.Equals((int)0)); // True
    Console.WriteLine(b.Equals(b)); // True
    Console.WriteLine(b == a); // True
    Console.WriteLine(b == 0); // True
    }
}
Run Code Online (Sandbox Code Playgroud)

这里有两个有趣的点(假设aintblong):

  1. a != b,但是b == a;
  2. (a.Equals(b)) != (a == b)

是否有任何理由以这种方式实施比较?

注意:如果它有任何区别,则使用.NET 4.

SLa*_*aks 27

通常,Equals()对于不同类型的对象,方法不应返回true.

a.Equals(b)调用int.Equals(object),只能为盒装Int32s 返回true :

public override bool Equals(Object obj) { 
    if (!(obj is Int32)) {
        return false;
    }
    return m_value == ((Int32)obj).m_value; 
}  
Run Code Online (Sandbox Code Playgroud)

b.Equals(a)long.Equals(long)隐式转换int为a 后调用long.
因此它long直接比较两个s,返回true.

为了更清楚地理解,请查看由这个更简单的示例生成的IL(打印True False True):

int a = 0;
long b = 0L;

Console.WriteLine(a == b);
Console.WriteLine(a.Equals(b));
Console.WriteLine(b.Equals(a));
Run Code Online (Sandbox Code Playgroud)
IL_0000:  ldc.i4.0    
IL_0001:  stloc.0     
IL_0002:  ldc.i4.0    
IL_0003:  conv.i8     
IL_0004:  stloc.1     

IL_0005:  ldloc.0     //Load a
IL_0006:  conv.i8     //Cast to long
IL_0007:  ldloc.1     //Load b
IL_0008:  ceq         //Native long equality check
IL_000A:  call        System.Console.WriteLine    //True

IL_000F:  ldloca.s    00            //Load the address of a to call a method on it
IL_0011:  ldloc.1                   //Load b
IL_0012:  box         System.Int64  //Box b to an Int64 Reference
IL_0017:  call        System.Int32.Equals
IL_001C:  call        System.Console.WriteLine    //False

IL_0021:  ldloca.s    01  //Load the address of b to call a method on it
IL_0023:  ldloc.0         //Load a
IL_0024:  conv.i8         //Convert a to Int64
IL_0025:  call        System.Int64.Equals
IL_002A:  call        System.Console.WriteLine    //True
Run Code Online (Sandbox Code Playgroud)

  • @paulius_l:我没有看到你的问题.根据规范,这里的所有行为都是正确的; 唯一不明显的部分是隐式转换为"long".你想改变什么? (4认同)