Search code examples
c#collectionshashcodeiequalitycomparer

Implementing EqualityCompare vs overriding GetHashCode and Equals


I created two classes almost identical. Both represent a Pair (x,y) but in one of them I overrode the GetHashCode and Equals methods. I was told that when the HashCode is different the Collections takes them as different elements and does not even bother to actually compare them with the equals. However, it turns out that I implemented an EqualityComparer for the class that do not override the GetHashCode and Equals and everything works fine even when the HashCodes are still different.

Take a look at my Console Project:

using System;
using System.Collections.Generic;
using System.Linq;

namespace matrixExample
{
    class Program
    {

        static void Main(string[] args)
        {
            Console.WriteLine("Same Hash but no insertion: as expected");
            HashSet<MyPair> hash = new HashSet<MyPair>();
            MyPair one = new MyPair { X = 10, Y = 2 };
            MyPair copyOfOne = new MyPair { X = 10, Y = 2 };
            Console.WriteLine(one.GetHashCode() + " " +  hash.Add(one));
            Console.WriteLine(copyOfOne.GetHashCode() + " " + hash.Add(copyOfOne));


            Console.WriteLine("-----------------------------------------");

            Console.WriteLine("Different Hash but no insertion! why?");
            HashSet<MyPairWithoutOverride> hash2 = new HashSet<MyPairWithoutOverride>(new SameHash());
            MyPairWithoutOverride a1 = new MyPairWithoutOverride { X = 10, Y = 2 };
            MyPairWithoutOverride a1copy = new MyPairWithoutOverride { X = 10, Y = 2 };
            Console.WriteLine(a1.GetHashCode() + " " + hash2.Add(a1));
            Console.WriteLine(a1copy.GetHashCode() + " " + hash2.Add(a1copy));

        }

        public class MyPair
        {
            public int X { get; set; }
            public int Y { get; set; }

            public override int GetHashCode()
            {
                return X * 10000 + Y;
            }

            public override bool Equals(object obj)
            {
                MyPair other = obj as MyPair;
                return X == other.X && Y == other.Y;
            }
        }

        public class MyPairWithoutOverride
        {
            public int X { get; set; }
            public int Y { get; set; }
        }

        public class SameHash : EqualityComparer<MyPairWithoutOverride>
        {
            public override bool Equals(MyPairWithoutOverride p1, MyPairWithoutOverride p2)
            {
                return p1.X == p2.X && p1.Y == p2.Y;
            }
            public override int GetHashCode(MyPairWithoutOverride i)
            {
                return base.GetHashCode();
            }
        }

    }
}

Solution

  • Your problem is here

    public override int GetHashCode(MyPairWithoutOverride i)
    {
        return base.GetHashCode();
    }
    

    You're returning base.GetHashCode() which is actually the hash code of the SameHash class. So you actually are returning the same hash code every single time.

    If you return i.GetHashCode() then it will behave as expected.