Reputation: 148524
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 :-(
Upvotes: 1
Views: 159
Reputation: 14902
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".
Upvotes: 0
Reputation: 44316
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.
Upvotes: 5
Reputation: 144126
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.
Upvotes: 8