2017-08-05 51 views
1

我有以下對象。比較對象,忽略成員的「訂單」

public class Foo 
{ 
    public int X { get; } 
    public int Y { get; } 

    public Foo(int x, int y) 
    { 
     this.X = x; 
     this.Y = y; 
    } 
} 

現在我想重載Equals和GetHashCode方法,其中這兩個物體應被視爲相等(和相同的哈希碼)。

var foo1 = new Foo(1, 2); 
var foo2 = new Foo(2, 1); 

我知道如何編寫Equals方法,但我與獲取散列碼方法鬥爭。

這就是我目前的版本:

public override int GetHashCode() 
{ 
    unchecked 
    { 
     return (_x * 397)^_y; 
    } 
} 

在我目前的 - 不工作的解決方案 - foo1有399的散列碼和foo2的有795

我需要兩個是相同的。

+0

你爲什麼不檢查之前如果 –

+0

如果順序真的沒有關係,爲什麼不總是在構造函數中將最小值賦給x,將最大值賦給y? – juharr

+0

@juharr沒有想過它,但它的一部分約翰吳的回答 –

回答

5

您需要進行轉換,以便f(x,y) = f(y,x)。我可以想到一些應該這樣做的數學性質 - 任何可交換的東西都應該起作用,例如,簡單的乘法。

public override int GetHashCode() 
{ 
    unchecked 
    { 
     return _x * _y; 
    } 
} 

不知道收斂的可能性有多大,而且對於大量字段可能會更棘手。作爲替代,你可以強制交換參數爲有序散列前:

public override int GetHashCode() 
{ 
    var x = Math.Min(_x, _y); 
    var y = Math.Max(_x, _y); 
    unchecked 
    { 
     return (x * 397)^y; 
    } 
} 

或者,如果有三個或多個字段:

public override int GetHashCode() 
{ 
    var a = new int[] { _x, _y, _z }; 
    Array.Sort(a); 
    unchecked 
    { 
     return ((a[0] * 397)^a[1]) * 397^a[2]; 
    } 
} 

可能與LINQ做一個聰明的方式,但你明白了。

+0

注意@ JohnWu的第二個例子可能更好對於大多數目的而言,如果哈希碼僅僅用於你的情況下的廉價身份檢查,那麼他的第一個速度會更快,如果你用它來進行字典或條帶化等等,那麼他的第二個答案應該是mu總體來說更好。 – hoodaticus

+0

另請注意,Math.Min應儘可能快地儘可能快。我想我上次檢查他們正在使用最佳的二進制技術。 – hoodaticus

+0

@hoodaticus是的,我用它作爲字典中的一個關鍵字 –