2012-02-16 115 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

相关问题