2012-02-16 111 views
113

我想了解應該使用IEqualityComparer<T>IEquatable<T>的情況。 兩者的MSDN文檔看起來非常相似。IEqualityComparer <T>和IEquatable <T>和有什麼不一樣?

+3

這個問題需要更多upvotes! – nawfal 2012-12-06 11:03:50

+1

[MSDN sez:](https://msdn.microsoft.com/en-us/library/ms132151(v = vs.110).aspx)「此接口允許爲集合實現自定義相等比較**。 *「當然是在所選答案中推斷的。因爲'EqualityComparer '使用'IEquatable ' – radarbob 2016-09-20 18:38:14

+0

'測試相等性......上述建議我應該爲任何執行'IEquatable '的'T'創建一個自定義集合。像「List 」這樣的集合在其中是否存在某種微妙的錯誤? – radarbob 2016-09-20 18:45:09

回答

94

IEqualityComparer<T>是一個對象的接口,用於對T類型的兩個對象執行比較。

IEquatable<T>適用於T類型的對象,以便它可以與另一個對比。

+34

+1 _IEquatable用於對象,以便它可以將其自身與相同類型的另一個**進行比較** – gdoron 2012-02-16 18:30:57

+0

簡單,簡明且易於理解 – Tilak 2012-02-16 18:31:07

+0

同上@Tilak ....不需要更多解釋 – rajibdotnet 2014-05-18 21:02:36

3

比較兩個T s。另一個可以與其他T相比較。通常,你只需要一次使用一個,而不是兩個。

9

IEqualityComparer用於兩個對象的相等性在外部實現,例如,如果你想爲兩種類型定義一個你沒有源代碼的比較器,或者兩種東西之間的相等只在某些有限的情況下才有意義。

IEquatable是爲了實現對象本身(被比較的是相等的)。

+0

之間的差異同樣是唯一真正提出了「插入平等」(外部使用)問題的人加上1. – 2015-08-16 07:46:39

16

您已經得到了的基本定義,它們是。簡而言之,如果在類T上執行IEquatable<T>,Equals方法,該類型爲T的對象會告訴您對象本身(正在測試的相等性)是否等於另一個相同類型的實例T。而IEqualityComparer<T>用於測試任何兩個T實例的相等性,通常在T實例的範圍之外。

至於它們對於最初可能會引起混淆。根據定義,應該清楚的是,因此IEquatable<T>(在類別T中定義)應該成爲表示其對象/實例的唯一性的事實標準。 HashSet<T>Dictionary<T, U>(考慮GetHashCode也被覆蓋),ContainsList<T>等使用此。在T上實施IEqualityComparer<T>對上述一般情況沒有幫助。隨後,在除T以外的任何其他類別上實施IEquatable<T>價值不大。這個:

class MyClass : IEquatable<T> 

很少有道理。

在另一方面

class T : IEquatable<T> 
{ 
    //override ==, !=, GetHashCode and non generic Equals as well 

    public bool Equals(T other) 
    { 
     //.... 
    } 
} 

是它應該怎麼做。

IEqualityComparer<T>在需要自定義驗證相等性時非常有用,但不作爲一般規則。例如,在Person的某個等級中,您可能需要根據年齡測試兩個人的平等。在這種情況下,你可以這樣做:

class Person 
{ 
    public int Age; 
} 

class AgeEqualityTester : IEqualityComparer<Person> 
{ 
    public bool Equals(Person x, Person y) 
    { 
     return x.Age == y.Age; 
    } 

    public int GetHashCode(Person obj) 
    { 
     return obj.Age.GetHashCode; 
    } 
} 

對它們進行測試,嘗試

var people = new Person[] { new Person { age = 23 } }; 
Person p = new Person() { age = 23 }; 

print people.Contains(p); //false; 
print people.Contains(p, new AgeEqualityTester()); //true 

同樣IEqualityComparer<T>T沒有意義。

class Person : IEqualityComparer<Person> 

確實有效,但對眼睛看起來並不好,並且打敗了邏輯。

通常情況下,你需要的是IEquatable<T>。理想情況下,您可以只有一個IEquatable<T>,而根據不同的標準可以有多個IEqualityComparer<T>

IEqualityComparer<T>IEquatable<T>是完全類似Comparer<T>IComparable<T>其用於比較目的,而不是等同;良好的線程here,我寫了同樣的答案:)

+0

'public int GetHashCode(Person obj)'應該返回'obj.GetHashCode()' – 2016-12-02 18:16:14

+0

@HristoYankov應該返回'obj.Age.GetHashCode'。將編輯。 – nawfal 2016-12-02 18:18:28

+0

請解釋爲什麼比較器必須對它比較的對象的哈希值做出這樣的假設?你的比較器不知道人如何計算哈希值,爲什麼你會覆蓋它? – 2016-12-02 19:53:01

36

在決定是否使用IEquatable<T>IEqualityComparer<T>, 人們可能要問:

有測試T兩個實例爲平等的首選方式,或者有幾種同樣有效的方法?

  • 如果測試相等的T兩個實例,或者幾種方法之一是首選,然後IEquatable<T>將是正確的選擇的方法只有一個:這個接口應該只執行T本身,因此T的一個實例具有關於如何將其本身與另一個T實例進行比較的內部知識。

  • 在另一方面,如果有比較兩個T S代表平等幾個同樣合理的方法,IEqualityComparer<T>似乎更爲合適:此接口並不意味着由T本身來實現,而是通過其他的「外部」類。因此,在測試兩個實例T以獲得相等時,由於T對平等沒有內在的理解,因此您必須明確選擇一個根據您的具體要求執行測試的實例。

例子:

讓我們考慮這兩種類型(假設有value semantics):

interface IIntPoint : IEquatable<IIntPoint> 
{ 
    int X { get; } 
    int Y { get; } 
} 

interface IDoublePoint // does not inherit IEquatable<IDoublePoint>; see below. 
{ 
    double X { get; } 
    double Y { get; } 
} 

爲什麼會只有一個這種類型的繼承IEquatable<>的,而不是其他?

理論上,只有一種比較兩種實例類型的明智方式:如果兩個實例中的XY屬性相等,則它們相等。根據這種想法,這兩種類型都應該執行IEquatable<>,因爲似乎沒有其他有意義的方式進行平等測試。

這裏的問題是,comparing floating-point numbers for equality might not work as expected, due to minute rounding errors。有幾種不同的方法可以比較近似等於的浮點數,每種方法都具有特定的優點和折衷方案,您可能希望能夠選擇適合自己的方法。

sealed class DoublePointNearEqualityComparerByTolerance : IEqualityComparer<IDoublePoint> 
{ 
    public DoublePointNearEqualityComparerByTolerance(double tolerance) { … } 
    … 
    public bool Equals(IDoublePoint a, IDoublePoint b) 
    { 
     return Math.Abs(a.X - b.X) <= tolerance && Math.Abs(a.Y - b.Y) <= tolerance; 
    } 
    … 
} 

請注意,鏈接到(上面)的頁面明確指出,該測試近乎平等有一些缺點。由於這是一個IEqualityComparer<T>的實現,如果它不夠用於您的目的,您可以將其交換出來。

+4

由於任何合法的'IEqualityComparer '實現*必須*實現等價關係,這意味着在所有*情況下兩個對象相等於三分之一,所以它們必須被破壞*比較相等。以與上述相反的方式實施「IEquatable 」或「IEqualityComparer 」的任何類都被打破。 – supercat 2013-03-19 19:59:06

+3

更好的例子是字符串之間的比較。只有字符串包含相同的字節序列時,纔將字符串視爲相等的字符串比較方法是有意義的,但還有其他有用的比較方法*也構成了等價關係*,例如不區分大小寫的比較。請注意,認爲「hello」等於「Hello」和「hElLo」的'IEqualityComparer '必須考慮「Hello」和「hElLo」彼此相等,但對於大多數不會成爲問題的比較方法。 – supercat 2013-03-19 20:03:20

+0

@supercat,感謝您的寶貴意見。我很可能在接下來的幾天內不會修改我的答案,所以如果您願意,請隨時根據需要進行修改。 – stakx 2013-03-20 08:28:54

相關問題