Search code examples
c#dictionary.net-corehashtable

Dictionary with Tuple as Key GetHashCode is not called


Description


Trying to create a Dictionary with Tuple as the key.

However the GetHashCode and Equals functions are not being called, hence duplicate keys will be added to the dictionary.

This is the Keyclass that I want to use as my Dictionary's key:

class Key : IEqualityComparer<Tuple<int, int>>
    {
        private Tuple<int, int> _tuple;

        public Key(int a, int b)
        {
            _tuple = new Tuple<int, int>(a, b);
        }


        public bool Equals(Tuple<int, int> x, Tuple<int, int> y)
        {
            return (x.Item1 == y.Item1 && x.Item2 == y.Item2);
        }

        public int GetHashCode(Tuple<int, int> obj)
        {
            return obj.Item1.GetHashCode() ^ obj.Item2.GetHashCode();
        }
    }

Driver code:

public static void Main() {

    var map = new Dictionary<Key, int>();

    map.Add(new Key(1, 2), 3);
    map.Add(new Key(1, 2), 4); // <==== Should not add!
}

Questions


How to fix this?

What is the easiest implementation for Dictionary<Tuple<int, int>, int> to work properly?


Solution

  • If you want to use own class Key:

        public class Key
        {
            public Key(int item1, int item2)
            {
                Tuple = new Tuple<int, int>(item1, item2);
            }
    
            public override bool Equals(object obj)
            {
                if (obj == null)
                {
                    return false;
                }
    
                if (obj is Key other)
                {
                    return Tuple.Equals(other.Tuple);
                }
    
                return false;
            }
    
            public override int GetHashCode()
            {
                return Tuple.GetHashCode();
            }
    
            public Tuple<int, int> Tuple { get; private set; }
        }
    
        public void Do()
        {
            var map = new Dictionary<Key, int>();
            map.Add(new Key(1, 2), 3);
            map.Add(new Key(1, 2), 4); // will throw System.ArgumentException
        }
    

    Another way is just using Tuple class:

        public void Do()
        {
            var map = new Dictionary<Tuple<int, int>, int>();
            map.Add(new Tuple<int, int>(1, 2), 3);
            map.Add(new Tuple<int, int>(1, 2), 4); // will throw System.ArgumentException
        }