![](/img/trans.png)
[英]Differences between IEquatable<T>, IEqualityComparer<T>, and overriding .Equals() when using LINQ on a custom object collection?
[英]What is the difference between IEqualityComparer<T> and IEquatable<T>?
IEqualityComparer<T>
是一个对象的接口, IEqualityComparer<T>
两个T
类型的对象执行比较。
IEquatable<T>
用于类型T
的对象,以便它可以将自己与另一个相同类型的对象进行比较。
在决定是使用IEquatable<T>
还是IEqualityComparer<T>
,人们可能会问:
是否有测试
T
两个实例是否相等的首选方法,或者是否有几种同样有效的方法?
如果只有一种方法可以测试T
两个实例是否相等,或者首选几种方法之一,那么IEquatable<T>
将是正确的选择:该接口应该仅由T
本身实现,因此一个T
实例具有如何将自身与T
另一个实例进行比较的内部知识。
另一方面,如果有几种同样合理的方法来比较两个T
是否相等, IEqualityComparer<T>
似乎更合适:该接口不是由T
本身实现,而是由其他“外部”类实现。 因此,测试的两种情况下, T
的平等,因为T
具有平等的内部没有理解,你将不得不做出的明确选择IEqualityComparer<T>
实例根据您的具体要求执行测试。
例子:
让我们考虑这两种类型(它们应该具有值语义):
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<>
,而另一种不继承?
理论上,比较任一类型的两个实例只有一种合理的方法:如果两个实例中的X
和Y
属性相等,则它们相等。 根据这种想法,两种类型都应该实现IEquatable<>
,因为似乎没有其他有意义的方法来进行相等测试。
这里的问题是,由于微小的舍入误差,比较浮点数的相等性可能无法按预期工作。 有多种比较浮点数以实现近似相等的方法,每种方法都有特定的优势和权衡,您可能希望能够自己选择哪种方法是合适的。
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>
实现,如果它对您的目的来说不够好,您可以简单地将其换掉。
您已经获得了它们的基本定义。 总之,如果实现IEquatable<T>
上类T
,所述Equals
类型的对象上的方法T
告诉你如果对象本身(一个用于平等被测试)等于相同类型的另一个实例T
。 而, IEqualityComparer<T>
是用于测试的任何两个实例的平等T
,的实例的典型外部范围T
。
至于它们的用途,一开始可能会令人困惑。 从定义中应该很清楚,因此IEquatable<T>
(在类T
本身中定义)应该是表示其对象/实例唯一性的事实上的标准。 HashSet<T>
, Dictionary<T, U>
(考虑到GetHashCode
也被覆盖), Contains
在List<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>
完全类似,它们用于比较目的而不是等同; 这里是一个很好的线程,我在这里写了相同的答案:)
IEqualityComparer 用于在外部实现两个对象的相等性时使用,例如,如果您想为没有源的两种类型定义一个比较器,或者对于两个事物之间的相等性仅在某些有限上下文中有意义的情况。
IEquatable 是为对象本身(被比较为相等的对象)来实现的。
一个比较两个T
。 另一个可以将自己与其他T
进行比较。 通常,您一次只需要使用一个,而不是两个都使用。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.