I have the following example:
namespace ComparisonExample
{
class Program
{
static void Main(string[] args)
{
var hello1 = new Hello();
var hello2 = new Hello();
// calls Hello.Equals
var compareExplicitly = hello1.Equals(hello2);
// calls Object.Equals
var compareWithGenerics = ObjectsEqual<Hello>(hello1, hello2);
}
private static bool ObjectsEqual<TValue>(TValue value1, TValue value2)
{
return value1.Equals(value2);
}
}
class Hello : IEquatable<Hello>
{
public bool Equals(Hello other)
{
return true; // doesn't matter
}
}
}
The question is why in the second "Equals" call I'm redirected to Object.Equals instead of Hello.Equals even though I'm specifying the exact type in generic argument?
Because you haven't told the generic method that your object implements
IEquatable<T>
:Try now with:
In your
ObjectsEqual
method you have access only to methods/properties/fields ofTValue
that are defined in theobject
class plus the methods that are defined in the interfaces/base classes defined in the constraints. No constraints => you have access only toEquals(object)
,GetHashCode()
,GetType()
, (and if you have the constraintclass
:operator==
,operator!=
.) Of these two are virtual (Equals(object)
,GetHashCode()
), so you'll use the "correct" version, the third isn't normally overwritten (GetType()
), so you'll probably use the "correct" version. Only the two operators==
/!=
are often overwritten and lo and behold! In your generic method you can't use the "correct" version of the two! :-)