2009-06-08 29 views
4

我有一個類,它看起來像這樣:問題有關字典<T,T>

public class NumericalRange:IEquatable<NumericalRange> 
    { 
     public double LowerLimit; 
     public double UpperLimit; 

     public NumericalRange(double lower, double upper) 
     { 
      LowerLimit = lower; 
      UpperLimit = upper; 
     } 

     public bool DoesLieInRange(double n) 
     { 
      if (LowerLimit <= n && n <= UpperLimit) 
       return true; 
      else 
       return false; 
     } 

     #region IEquatable<NumericalRange> Members 

     public bool Equals(NumericalRange other) 
     { 
      if (Double.IsNaN(this.LowerLimit)&& Double.IsNaN(other.LowerLimit)) 
      { 
       if (Double.IsNaN(this.UpperLimit) && Double.IsNaN(other.UpperLimit)) 
       { 
        return true; 
       } 
      } 

      if (this.LowerLimit == other.LowerLimit && this.UpperLimit == other.UpperLimit) 
       return true; 
      return false; 
     } 

     #endregion 
    } 

此類包含值的neumerical範圍。這個類還應該能夠保持默認範圍,其中LowerLimit和UpperLimit都等於Double.NaN。

現在這個類進入一個字典

的解釋工作正常,「非南的數值範圍值,但當關鍵是{NaN的不同,NaN} NumericalRange對象,那麼字典拋出一個KeyNotFoundException。

我在做什麼錯?是否還有其他需要實現的接口?

+1

你還重寫GetHashCode和equals(OBJ)? – Rauhotz 2009-06-08 06:52:02

+0

不需要這些覆蓋?如果是這樣,你如何實現GetHashCode? – ashwnacharya 2009-06-08 06:57:16

+1

見:http://stackoverflow.com/questions/371328/why-is-it-important-to-override-gethashcode-when-equals-method-is-overriden-in-c/371348#371348 – 2009-06-08 07:02:24

回答

12

根據你的評論,你還沒有實現GetHashCode。我很驚訝,這個類在所有工作在字典中,除非你總是要求你把在相同關鍵,我建議的類似的實現:

public override int GetHashCode() 
{ 
    int hash = 17; 
    hash = hash * 23 + UpperLimit.GetHashCode(); 
    hash = hash * 23 + LowerLimit.GetHashCode(); 
    return hash; 
} 

假定Double.GetHashCode()爲NaN提供了一致的值。 NaN當然有很多值,你可以可能想要特殊情況它確保他們都給相同的散列。

你也應該重寫Equals方法從Object繼承:

public override bool Equals(Object other) 
{ 
    return other != null && 
      other.GetType() == GetType() && 
      Equals((NumericalRange) other); 
} 

注意該類型可以進行檢查,通過使用as如果你封你的類更有效。否則,如果有人從你的另一個班級派生,你會在x.Equals(y)y.Equals(x)之間得到有趣的不對稱。平等與繼承變得棘手。

您應該使您的字段是私人的,暴露他們僅作爲資產。如果這將被用作字典中的關鍵字,我強烈建議使它們只讀。在字典中使用密鑰時更改密鑰的內容很可能會導致它稍後「不可信」。

7

GetHashCode方法的默認實現使用對象的引用而不是對象中的值。您必須使用與用於將數據放入字典中的對象相同的實例才能正常工作。

GetHashCode一個實現,它的作品簡單地從它的散列碼生成代碼的數據成員:

public int GetHashCode() { 
    return LowerLimit.GetHashCode()^UpperLimit.GetHashCode(); 
} 

(這是Point結構使用相同的實現。)

任何實現的當在Dictionary中使用時,始終返回任何給定參數值的相同哈希碼的方法都適用。僅僅爲所有值返回相同的哈希代碼實際上也是可行的,但是隨後字典的性能變差(查找關鍵字變爲O(n)操作而不是O(1)操作)。爲了獲得最佳性能,方法應該在範圍內均勻分配哈希代碼。

如果您的數據強烈的偏見,上面的實現可能不提供最佳性能。例如,如果你的範圍有很多,上下限是相同的,那麼它們都會得到散列碼零。在這種情況下,這樣的事情可能會工作得更好:

public int GetHashCode() { 
    return (LowerLimit.GetHashCode() * 251)^UpperLimit.GetHashCode(); 
} 

你應該考慮使類不可變的,即讓它的屬性爲只讀,只設置它們的構造。如果你在一個字典中改變一個對象的屬性,它的哈希碼將會改變,你將無法再訪問這個對象。