Consider this code:
int age = 25;
short newAge = 25;
Console.WriteLine(age == newAge); //true
Console.WriteLine(newAge.Equals(age)); //false
Console.ReadLine();
Both int
and short
are primitive types, but a comparison with ==
returns true and a comparison with Equals
returns false.
Why?
Equality is complicated.
Primitives types override the base object.Equals(object)
and return true if the boxed object
is of the same type and value. (Note that it will also work for nullable types; non-null nullable types always box to an instance of the underlying type.)
Since newAge
is a short
, its Equals(object)
method only returns true if you pass a boxed short with the same value. You're passing a boxed int
, so it returns false.
By contrast, the ==
operator is defined as taking two int
s (or short
s or long
s).
When you call it with an int
and a short
, the compiler will implicitly convert the short
to int
and compare the resulting int
s by value.
Primitive types also have their own Equals()
method that accepts the same type.
If you write age.Equals(newAge)
, the compiler will select int.Equals(int)
as the best overload and implicitly convert short
to int
. It will then return true
, since this method simply compares the int
s directly.
short
also has a short.Equals(short)
method, but int
cannot be implicitly converted to short
, so you aren't calling it.
You could force it to call this method with a cast:
Console.WriteLine(newAge.Equals((short)age)); // true
This will call short.Equals(short)
directly, without boxing. If age
is larger than 32767, it will throw an overflow exception.
You could also call the short.Equals(object)
overload, but explicitly pass a boxed object so that it gets the same type:
Console.WriteLine(newAge.Equals((object)(short)age)); // true
Like the previous alternative, this will throw an overflow if it doesn't fit in a short
.
Unlike the previous solution, it will box the short
into an object, wasting time and memory.
Here are both Equals()
methods from the actual source code:
public override bool Equals(Object obj) {
if (!(obj is Int16)) {
return false;
}
return m_value == ((Int16)obj).m_value;
}
public bool Equals(Int16 obj)
{
return m_value == obj;
}
See Eric Lippert.