Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
279 views
in Technique[技术] by (71.8m points)

c# - Why integer zero does not equal long zero?

A strange piece of code I've just discovered in C# (should also be true for other CLI languages using .NET's 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
    }
}

Two interesting points here (assuming that a is int and b is long):

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

Is there any reason why comparison was implemented this way?

Note: .NET 4 was used if it makes any difference.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

In general, Equals() methods are not supposed to return true for objects of different types.

a.Equals(b) calls int.Equals(object), which can only return true for boxed Int32s:

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

b.Equals(a) calls long.Equals(long) after implicitly converting the int to a long.
It therefore compares the two longs directly, returning true.

To understand more clearly, look at the IL generated by this simpler example (which prints True False True):

int a = 0;
long b = 0L;

Console.WriteLine(a == b);
Console.WriteLine(a.Equals(b));
Console.WriteLine(b.Equals(a));

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...