Question

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?

Was it helpful?

Solution

Because you haven't told the generic method that your object implements IEquatable<T>:

Try now with:

private static bool ObjectsEqual<TValue>(TValue value1, TValue value2) 
               where TValue : IEquatable<TValue> // IMPORTANT!!!
{
    return value1.Equals(value2);
}

In your ObjectsEqual method you have access only to methods/properties/fields of TValue that are defined in the object class plus the methods that are defined in the interfaces/base classes defined in the constraints. No constraints => you have access only to Equals(object), GetHashCode(), GetType(), (and if you have the constraint class: 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! :-)

OTHER TIPS

Addition from MSDN:

Unbounded Type Parameters.
Type parameters that have no constraints, such as T in public class SampleClass<T> { }, are called unbounded type parameters.
Unbounded type parameters have the following rules:

  • The != and == operators cannot be used because there is no guarantee that the concrete type argument will support these operators.
  • They can be converted to and from System.Object or explicitly converted to any interface type.
  • You can compare to null. If an unbounded parameter is compared to null, the comparison will always return false if the type argument is a value type.

In this case TValue is converted to System.Object and Equals method called.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top