2013-12-16 70 views
0

可以說我有類:我應該如何覆蓋HashSet的Equals和GetHashCode?

public class Ident 
    { 
     public String Name { get; set; } 
     public String SName { get; set; } 
    } 

,也多了一個:

class IdenNode 
    { 
     public Ident id { get; set; } 
     public List<IdenNode> Nodes { get; set; } 

     public IdenNode() 
     { 
      Nodes = new List<IdenNode>(); 
     } 
    } 

我想用HashSet<IdenNode>與記住,這兩個元素是相同的(等於)當且僅當他們的ID 。名字是平等的。

所以,我要重寫EqualsGetHashCode像下一個:

 public override bool Equals(object obj) 
     { 
      IdenNode otherNode = obj as IdenNode; 

      return otherNode != null && otherNode.id != null && id.Name == otherNode.id.Name; 
     } 

     public override int GetHashCode() 
     { 
      if (id != null) 
       return id.Name.GetHashCode(); 
      else 
       // what should I write here? 
     } 

我是覺得對嗎?如果是,我應該在GetHashCode中放置什麼?

UPDATE

能告訴我是OK使用 「==」 和 「!=」 在equals方法?或者可能是ReferenceEquals或其他?

另外,我應該重寫運算符「==」和「!=」嗎?

+0

字符串是一個可怕的東西,用作標識符,區分大小寫等。你不能使用像int或GUID(是它的一個字符串,但它保證獨特的系統) – Maess

+0

@Maess使一個好點子。如果兩個人擁有相同的姓氏和名字會怎麼樣? –

+1

@Maess一個GUID不是一個字符串! :) –

回答

6

如果id(或id.Name)爲空,則返回0就完全正常了。Nullable<T>(如int?)爲「null」值返回0。

請記住,從GetHashCode()返回相同值的兩個對象並不意味着相等 - 它只意味着兩個對象可能是相等的。然而,翻轉是兩個「相等」對象必須返回相同的哈希碼。這兩個原則似乎都可以通過你的定義EqualsGetHashCode

+0

得到你關於返回0的意思。你能否告訴我是否應該重載運算符「==」和「!=」? – user2706838

+0

@mehow我應該澄清,「可空類型」我的意思是'可爲空'。 _Reference_ type不會返回_anything_,因爲您無法在空引用變量上調用'GetHashCode'。 –

+0

@DStanley完全有效的答案我只是想着可以爲空類型的'ToString()'方法。我的不好 - > +1給你 – 2013-12-16 14:10:18

3

當心零點!你有很多。照顧StackOverflow:嘗試不使用 ==和!=在Equals方法內。通常情況下,我們返回作爲哈希代碼的情況下,例如:

public override bool Equals(object obj) { 
    // Often we should compare an instance with itself, 
    // so let's have a special case for it (optimization) 
    if (Object.ReferenceEquals(obj, this)) 
    return true; 

    IdenNode other = obj as IdenNode; 

    // otherNode != null line in your code can cause StackOverflow: 
    // "!=" calls "Equals" which in turn calls "!=" etc... 
    if (Object.ReferenceEquals(null, other)) 
    return false; 

    // Id can be null 
    if (Object.ReferenceEquals(id, other.id)) 
    return true; 
    else if (Object.ReferenceEquals(id, null) || Object.ReferenceEquals(other.id, null)) 
    return false; 

    // Let's be exact when comparing strings: 
    // i.e. should we use current locale or not etc 
    return String.Equals(id.Name, other.id.Name, StringComparison.Ordinal); 
} 

public override int GetHashCode() { 
    // It's typical to return 0 in case of null 
    if (Object.ReferenceEquals(null, id)) 
    return 0; 
    else if (Object.ReferenceEquals(null, id.Name)) // <- Name can be null as well! 
    return 0; 

    return id.Name.GetHashCode(); 
} 
+1

明智的防守機制+1。 – Nair

+0

非常感謝,這看起來像我想要的。你能告訴我在我的情況下是否應該重寫「==」和「!=」? – user2706838

+0

@ user2706838:你不需要重寫它們,但是,恕我直言,你最好這樣做 –

2

我應該把什麼GetHashCode的,如果這樣的嗎?

返回零是好的。請注意,在名稱上定義值的平等是一個壞主意;我知道在美國至少有另外三個Eric Lippert,他們不是我。字面上有數百萬人,可能有數十億人有名字相撞。

請問我可以在Equals方法中使用「==」和「!=」嗎?或者可能是ReferenceEquals或其他?

我的建議是:混合參考值和值相等時,應該很清楚。如果你打算引用平等,那就這樣說。

此外,我應該重寫運算符「==」和「!=」嗎?

是的。令人困惑的是Equals意味着一件事而==意味着另一件事。

相關問題