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.