В чем разница между IEqualityComparer и IEquatable?
Я хочу понять сценарии, где IEqualityComparer<T> и IEquatable<T> должен быть использован.
Документация MSDN для обоих выглядит очень похоже.
5 ответов:
IEqualityComparer<T>- это интерфейс для объекта, который выполняет сравнение двух объектов типаT.
IEquatable<T>для объекта типаTчтобы он мог сравнить себя с другим.
при использовании
IEquatable<T>илиIEqualityComparer<T>, можно было бы спросить:есть ли предпочтительный способ тестирования двух экземпляров
Tдля равенства, или есть несколько одинаково действительных способов?
если есть только один способ тестирования двух экземпляров
Tдля равенства, или если один из нескольких методов является предпочтительным, тоIEquatable<T>был бы правильный выбор: этот интерфейс предполагается быть реализованным только с помощьюTсам, так что один экземплярTимеет внутреннее знание о том, как сравнить себя с другим экземпляромT.С другой стороны, если есть несколько одинаково разумные способы сравнения двух
Ts для равенства,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переопределяется, а),ContainsonList<T>и т. д. воспользоваться этим. РеализацияIEqualityComparer<T>onTне помогает в вышеупомянутых общих случаях. Впоследствии, есть небольшое значение для реализацииIEquatable<T>по любому другой класс, кроме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>onTне имеет смысла.class Person : IEqualityComparer<Person>правда это работает, но не выглядит хорошо для глаз и побеждает логику.
обычно то, что вам нужно-это
IEquatable<T>. Также В идеале вы можете иметь только одинIEquatable<T>в то время как несколькоIEqualityComparer<T>возможна на основе различных критериев.The
IEqualityComparer<T>иIEquatable<T>точно аналогичныComparer<T>иIComparable<T>которые используются для сравнения вместо того, чтобы приравнивать; хорошая нить здесь где я написал тот же ответ:)
IEqualityComparer используется, когда равенство двух объектов реализуется извне, например, если вы хотите определить компаратор для двух типов, для которых у вас не было источника, или для случаев, когда равенство между двумя вещами имеет смысл только в некотором ограниченном контексте.
IEquatable для самого объекта (тот, который сравнивается для равенства) для реализации.
сравнить два
Tы. Другой может сравнить себя с другимиTs. Как правило, вам нужно будет использовать только один в то время, а не оба.
Comments