0

並行辞書で自作の 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上記のコードは、テストして問題を再現するためのものです。

4

1 に答える 1

1

これによると、長いハッシュ コードは使用できないため、質問に対する答えはノーです。

ただし、一意の値の代わりに一意の組み合わせを使用できます。解決策は、パーティショニング システムを実装することです。つまり、次のような辞書の辞書を用意します。

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);
    }
}

このようにして、ハッシュ コードのリストが作成され、各ハッシュ コードには再びハッシュ コードのリストが作成され、組み合わせは一意になります。ただし、読み取りと書き込みは2つのステップで行われます(パフォーマンスのために一意のハッシュが必要な場合に考慮してください)。

それが役に立てば幸い。

于 2014-03-19T11:15:30.460 に答える