並行辞書で自作の IEqualityComparer と GetHashCode を使用すると問題が発生します。
以下のクラス (2 つのプロパティを使用して簡略化) は、次のように実装すると完璧に機能します。
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
}
ほぼ同じクラスを作成しましたが、通常の IEqualityComparer インターフェースの代わりに少し変更を加えたので、long / int64 hascodes を生成できました (クラスが保持するプロパティがますます多くなると、同じハッシュコードを持つ複数の値に遭遇するため)。
だから私は同じハスコードを取得する変更を減らしたかった. したがって、より大きな数値を使用し、可能であれば 10000 を掛けて、アクションの小数もいくつか取得したいと考えました。
したがって、私はこのインターフェースを作成しました:
public interface IEqualityComparerInt64<in T>
{
bool Equals(T x, T y);
Int64 GetHashCode(T obj);
}
プロパティクラスを変更して、次のようにします。
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 はうまくいきました。これまでのところ問題ありません。
しかし...次のようにIEqualityComparerをconcurrentdictionaryに追加しようとすると:
ConcurrentDictionary<TwoUintsKeyInfoInt64,Int64> hashCodePlusIandJDict = new ConcurrentDictionary<TwoUintsKeyInfoInt64, Int64>(new TwoUintsKeyInfoInt64.EqualityComparerOneUintAndTwoStringKeyInfo());
次のエラーが表示されます。
エラー 3 引数 1: 'HasCodeTestForUniqueResult.TwoUintsKeyInfoInt64.EqualityComparerOneUintAndTwoStringKeyInfo' から 'System.Collections.Generic.IEqualityComparer' に変換できません D:\Users\mldz\Documents\visual studio 2012\HashCodeTestForUniqueResult\HashCodeTestForUniqueResult\Form1.cs 109 140 HashCodeTestForUniqueResult
デフォルトの System.Collections.Generic.IEqualityComparer の int 型と、独自の GetHashCode ジェネレーターからの long / int64 の結果との間に競合があることを理解しています。しかし、これを解決して長いハッシュコードを使用できるようにする方法はありますか?
敬具、
マティス
PS上記のコードは、テストして問題を再現するためのものです。