简体   繁体   中英

Object.Equals clarification in C#?

I've made a simple test :

     object t = 3;
     object aa = 3;
#1   Console.WriteLine(t.Equals(aa));  
#2   Console.WriteLine(t.Equals(3));  
#3   Console.WriteLine(3.Equals(aa));  

All of them are true.(that's my problem actually).

looking at object , this is the used function:

 public virtual bool Equals(object obj);

The equals is virtual. so it can be overridden.

But I don't see any polymorphic behavior. this is just a pure boxed value.

  • Regarding line #1 t.Equals(aa)

    The reference type is the static type - Object.

    so I thought it should call Object.Equals : which means that the reference are different , meaning the first answer should be False .(and I probably wrong here). why is that?

  • Regarding line #2 t.Equals(3)

    Again, t's static type is object. so Object.Equals is running. how come it is true ?

  • Regarding line #3 3.Equals(aa)

    I believe it is the public override bool Equals(object obj); is running because the static type is in t. and the param type is object. but why does it true ? does it un-box the value ?

it seems that something , somehow unboxes the object without my notice :-(

Object s Equals method is polymorphic, so it can be overriden by subtypes like int . Int32.Equals overrides this method to do a value comparison between the current object and its argument, and since the arguments are equal once unboxed, it returns true.

There are two overload of Int32.Equals - bool Equals(object) and bool Equals(int) . The bool Equals(object) overload is the one overriden from object . Since t and aa are object references, this is the method which will be called in examples 1 and 2.

In example 3, it is still this overload which is called since aa is an object and this is therefore the only valid overload.

The == operator is static and is resolved statically based on the types of its arguments, which are both object in your example. The == operator for object compares references, and in this case will return false for two separate boxed ints.

The virtual method Object.Equals is being called, but because of the way virtual methods work, it calls the Int32.Equals method instead, which compares the int values, not the references.

Virtual methods are bound at runtime. That is, they choose the appropriate method at runtime, not at compile time. In this case, Object.Equals is what is in the compiled code, but since you're comparing int s, it chooses Int32.Equals at runtime. This is accomplished using something called v-tables (in case you wanted to read more on this).

Keep in mind that Equals is supposed to act like this, and if you really want reference equality, you can use ReferenceEquals .

Note that this doesn't have anything to do with boxing. You'll get the same behaviour with, for example, a string , or a custom class.

As you wrote in your question the following Asserts will all pass

[Test] 
public void EqualityOnInts()
{
    object a = 1;
    object b = 1;

    Assert.AreEqual(a, b);
    Assert.IsTrue(1.Equals(a));
    Assert.IsTrue(b.Equals(1));
}

If you instantiate a you create a new integer object with value 1. Calling the Equals method on a will result in calling the Equals method on Int32 . Also, if you do a.GetType() it will return Int32`.

Since the Equals implementation of Int32 will check if the value is equal, and does not care about a different object reference, the result will be "true".

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM