Question

I have a problem using a self made IEqualityComparer and GetHashCode in a concurrent dictionary.

The class below (simplified with used two properties) works perfect when I implement it like this:

ConcurrentDictionary<TwoUintsKeyInfo,Int64> hashCodePlusIandJDict = new ConcurrentDictionary<TwoUintsKeyInfo, Int64>();

.

public class TwoUintsKeyInfo
{
    public uint IdOne { get; set; }
    public uint IdTwo { get; set; }

    #region Implemetation of the IEqualityComparer

    public class EqualityComparerTwoUintsKeyInfo : IEqualityComparer<TwoUintsKeyInfo>
    {
        System.Reflection.PropertyInfo[] properties;
        bool propertyArraySet=false;

        public int GetHashCode(TwoUintsKeyInfo obj)
        {
            unchecked
            {
                if(!propertyArraySet)
                {
                    properties = obj.GetType().GetProperties().OrderBy(x => x.Name).ToArray();
                    propertyArraySet = true;
                }

                decimal hash = 17;
                int counter=0;
                foreach(System.Reflection.PropertyInfo p in properties)
                {
                    counter++;
                    var value = p.GetValue(obj);
                    decimal unique = (decimal)Math.Pow(Math.E, counter);
                    hash = hash + (value == null ? unique : value.GetHashCode() * unique);
                }
                return 2147483647M * .001M > hash ? (int)(hash * 1000) : (int)hash;
            }
        }

        public bool Equals(TwoUintsKeyInfo x, TwoUintsKeyInfo y)
        {
            return GetHashCode(x) == GetHashCode(y);
        }
    }

    #endregion Implemetation of the IEqualityComparer
}

Now I made almost the same class, but instead of the normal IEqualityComparer interface, I made a little change, so I could generate long / int64 hascodes (because when the class hold more and more properties, we encountered multiple values with the same hashcode)

So I wanted to reduce the changes of getting the same hascode. Therefore I wanted to use bigger numbers and if possible multiple by 10000 to get some of the decimals in on the action as well.

therefore I created this interface:

public interface IEqualityComparerInt64<in T>
{
    bool Equals(T x, T y);
    Int64 GetHashCode(T obj);
}

and altered the property class so it looks like this:

public class TwoUintsKeyInfoInt64
{
    public uint IdOne { get; set; }
    public uint IdTwo { get; set; }

    #region Implemetation of the IEqualityComparer

    public class EqualityComparerTwoUintsKeyInfoInt64 : IEqualityComparerInt64<TwoUintsKeyInfoInt64>
    {
        System.Reflection.PropertyInfo[] properties;
        bool propertyArraySet=false;
        decimal _upperThreshold,_lowerThreshold;

        public EqualityComparerTwoUintsKeyInfoInt64()
        {
            _upperThreshold = long.MaxValue * .0001M;
            _lowerThreshold = -long.MaxValue * .0001M;
        }

        public long GetHashCode(TwoUintsKeyInfoInt64 obj)
        {
            unchecked
            {
                if(!propertyArraySet)
                {
                    properties = obj.GetType().GetProperties().OrderBy(x => x.Name).ToArray();
                    propertyArraySet = true;
                }

                decimal hash = 17;
                int counter=0;
                foreach(System.Reflection.PropertyInfo p in properties)
                {
                    counter++;
                    var value = p.GetValue(obj);
                    decimal unique = (decimal)Math.Pow(Math.E, counter);
                    hash = hash + (value == null ? unique : value.GetHashCode() * unique);
                }
                return _upperThreshold > hash && _lowerThreshold < hash ? (long)(hash * 10000) : (long)hash;
            }
        }

        public bool Equals(TwoUintsKeyInfoInt64 x, TwoUintsKeyInfoInt64 y)
        {
            return GetHashCode(x) == GetHashCode(y);
        }
    }

    #endregion Implemetation of the IEqualityComparer
}

GetHashCode worked fine. So far no problem.

But...when I try to add a IEqualityComparer to the concurrentdictionary like this:

    ConcurrentDictionary<TwoUintsKeyInfoInt64,Int64> hashCodePlusIandJDict = new ConcurrentDictionary<TwoUintsKeyInfoInt64, Int64>(new TwoUintsKeyInfoInt64.EqualityComparerOneUintAndTwoStringKeyInfo());

I get this error:

Error 3 Argument 1: cannot convert from 'HasCodeTestForUniqueResult.TwoUintsKeyInfoInt64.EqualityComparerOneUintAndTwoStringKeyInfo' to 'System.Collections.Generic.IEqualityComparer' D:\Users\mldz\Documents\visual studio 2012\HashCodeTestForUniqueResult\HashCodeTestForUniqueResult\Form1.cs 109 140 HashCodeTestForUniqueResult

I understand that there's a conflict between the int type of the default System.Collections.Generic.IEqualityComparer and my long / int64 result from my own GetHashCode generator. But is there any way to solve this and be able to use long HashCodes?

Kind regards,

Matthijs

P.S. the code above is just to test it and replicate the problem.

Was it helpful?

Solution

According to this you cannot use long hash codes, so the answer to the question is no.

But you can have unique combinations instead of unique values; the solution is to implement a partitioning system, meaning have a dictionary of dictionaries, like:

public class MyClass 
{
    Dictionary<uint, Dictionary<uint, Int64>> PartDict;

    Int64 ReadValue(uint id1, uint id2)
    {
        return (PartDict[id1])[id2];
    }

    void AddValue(uint id1, uint id2, Int64 value)
    {
        Dictionary<uint, Int64> container;
        if (!PartDict.TryGetValue(id1, out container))
        {
            container = new Dictionary<uint, Int64>();
            PartDict.Add(id1, container);
        }
        container.Add(id2, value);
    }
}

This way you will have a list of hash codes and each hash code will have again a list of hash codes, the combination being unique. Any reading and writing will be done in 2 steps though (to consider in case you want unique hash for performance).

Hope it helps.

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