2014-03-13 30 views
0

我有一個問題,在併發字典中使用自制的IEqualityComparer和GetHashCode。使用long(int64)作爲hashCode,並仍然使用IEqualityComparer併發Dictionary

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接口,我做了一個小的變化,所以我可能會產生長/ Int64的hascodes(因爲上課的時候持有越來越多的特性,我們遇到具有相同哈希碼的多個值)

所以我想減少獲得相同hascode的變化。因此,我想使用更大的數字,如果可能的話使用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()); 

我得到這個錯誤:

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

據我所知,有int類型之間的衝突默認的System.Collections.Generic.IEqualityComparer和我自己的GetHashCode生成器的long/int64結果。但是有沒有什麼辦法可以解決這個問題,並且可以使用長的HashCodes?

親切的問候,

Matthijs

附:上面的代碼只是爲了測試它並重現問題。

+0

爲什麼要長時間創建自己的數據類型? (參考TwoUintsKeyInfoInt64) – Matthew

+0

你是什麼意思?我想讓GetHashCode更精確(閱讀:減少對具有相同哈希碼的不同值的更改) – user369122

+0

作爲一個方面說明,這是不好的:'公共布爾等於(TwoUintsKeyInfo x,TwoUintsKeyInfo y){return GetHashCode(x) == GetHashCode(y); }'。正如你自己指出的那樣,相同的哈希碼並不一定意味着這兩個對象是相同的。如果兩個對象完全相同,那麼Equal只應該返回「true」。 –

回答

1

根據this你不能使用長哈希碼,所以問題的答案是否定的。

但是,您可以擁有唯一的組合而不是唯一的值;該解決方案是實現一個分區系統,這意味着有字典的字典,如:

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

這樣,您將擁有的散列碼列表以及每個哈希碼將再次有散列碼的列表,組合獨一無二。任何閱讀和寫作都將分兩步完成(考慮如果你想要獨特的哈希性能)。

希望它有幫助。

+0

嗨,我實際上實現了一個類似的解決方案來實現它。這似乎是好的。所以,儘管我已經有過這樣的事情;檢查答案;-)並感謝您的答覆 – user369122

相關問題