Why integer zero does not equal long zero?

后端 未结 6 713
天命终不由人
天命终不由人 2020-12-11 00:28

A strange piece of code I\'ve just discovered in C# (should also be true for other CLI languages using .NET\'s structs).



        
相关标签:
6条回答
  • 2020-12-11 01:00

    There is also the issue of narrowing or widening conversion. A long zero is always equal to an int zero, but not the other way around.

    When a long is compared to an int, only the least significant 32-bits are compared and the rest are ignored, thus the int.Equals(long) operation cannot guarantee equality even if the lower bits match.

    int a = 0;
    long b = 0;
    
    Trace.Assert(a.Equals((int)b));     // True   32bits compared to 32bits
    Trace.Assert(a.Equals((long)b));    // False  32bits compared to 64bits (widening)
    Trace.Assert(b.Equals((long)a));    // True   64bits compared to 64bits
    Trace.Assert(b.Equals((int)a));     // True   64bits compared to 32bits (narrowing)
    

    Also consider the case where the lower 32-bits are equal, but the upper ones are not.

    uint a = 0;
    ulong b = 0xFFFFFF000000;
    Trace.Assert((uint)a == (uint)b);  // true because of a narrowing conversion
    Trace.Assert((ulong)a == (ulong)b);  // false because of a widening conversion
    
    0 讨论(0)
  • 2020-12-11 01:01

    C# doesn't do automatic casting. Equals function compares types as well as values. Much like === in JS.

    0 讨论(0)
  • 2020-12-11 01:09

    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
    
    0 讨论(0)
  • 2020-12-11 01:09

    They are not the same because even simple types are inherited from System.Object - they are actually objects, and different object types, even with the same property values are not equal.

    Example:

    You could have a Co-Worker object with only one property: Name (string) and a partner object with only one property: Name (string)

    Co-worker David is not the same as Parner David. The fact that they are different object types sets them apart.

    In your case, using .Equals(), you're not comparing values, you're comparing objects. The object isn't "0" it's a System.Int32 with a Value of zero, and a System.Int64 with a value of zero.

    Code sample based on question in comment below:

    class CoWorker
    {
       public string Name { get; set; }
    }
    
    class Partner
    {
       public string Name { get; set; }
    }
    
    private void button1_Click(object sender, RoutedEventArgs e)
    {
       CoWorker cw = new CoWorker();
       cw.Name = "David Stratton";
       Partner p = new Partner();
       p.Name = "David Stratton";
    
       label1.Content = cw.Equals(p).ToString();  // sets the Content to "false"
    }
    
    0 讨论(0)
  • 2020-12-11 01:12

    Operator and method overloads, as well as conversion operators, are evaluated at compile time, unlike virtual-method overrides which are evaluated at run-time. The expression someIntVar.Equals(someNumericQuantity) is completely unrelated to the expression someObjectVarThatHoldsAnInt.Equals(someNumericQuantity). If you were to pretend the virtual method Object.Equals has a different name (like IsEquivalentTo), and substitute that name every place the virtual method is used, this would be much clearer. An integer zero may be numerically equal to a long zero, but that does not mean they are semantically equivalent.

    Such a separation in meaning between Equals and IsEquivalentTo, incidentally, would also have helped to avoid murkiness in the definition of the latter. It's possible to define a meaningful equivalence relation for arbitrary objects: storage location X should be considered equivalent to storage location Y if the behavior of all members of the former will always be equivalent to the corresponding members of the latter, and the only way to determine whether X and Y refer to the same object would be to use Reflection or ReferenceEquals. Even though 1.0m.Equals(1.00m) is and should be true, 1.0m.IsEquivalentTo(1.00m) should be false. Unfortunately, the use of the same name for the object equivalency-test method and the Decimal numerical-equality-test method led Microsoft to define the former to behave like the latter.

    0 讨论(0)
  • 2020-12-11 01:16

    because Equals compares objects and the a and b objects are different. They have the same value but are different as objects

    This link may help you: http://msdn.microsoft.com/en-us/library/ms173147(v=vs.80).aspx

    0 讨论(0)
提交回复
热议问题