Я хочу понять сценарии, где IEqualityComparer<T>
и IEquatable<T>
должны быть использованы. Документация MSDN для обоих выглядит очень похоже.
151
Я хочу понять сценарии, где IEqualityComparer<T>
и IEquatable<T>
должны быть использованы. Документация MSDN для обоих выглядит очень похоже.
EqualityComparer<T>
вместо реализации интерфейса ", потому чтоEqualityComparer<T>
тестирует равенство, используяIEquatable<T>
T
реализацииIEquatable<T>
. Может ли в коллекцииList<T>
быть какая-то тонкая ошибка?Ответы:
IEqualityComparer<T>
является интерфейсом для объекта, который выполняет сравнение двух объектов типаT
.IEquatable<T>
для объекта типа,T
чтобы он мог сравнивать себя с другим объектом того же типа.источник
IEqualityComparer<T>
- это интерфейс для объекта (который обычно отличается от легкого классаT
), который предоставляет функции сравнения, которые работаютT
Решая, использовать ли
IEquatable<T>
илиIEqualityComparer<T>
, можно спросить:Если существует только один способ проверки двух экземпляров
T
на равенство или если предпочтителен один из нескольких методов, тогдаIEquatable<T>
будет правильным выбором: этот интерфейс должен быть реализован толькоT
сам по себе, так что один экземплярT
имеет внутренние знания о как сравнить себя с другим экземпляромT
.С другой стороны, если есть несколько одинаково разумных методов сравнения двух
T
s на равенство,IEqualityComparer<T>
может показаться более подходящим: этот интерфейс предназначен не для реализацииT
сам по себе, а для других «внешних» классов. Следовательно, при проверке двух экземпляровT
на равенство, посколькуT
внутреннее понимание равенства отсутствует, вам придется сделать явный выборIEqualityComparer<T>
экземпляра, который выполняет тест в соответствии с вашими конкретными требованиями.Пример:
Давайте рассмотрим эти два типа (которые должны иметь семантику значений ):
Почему только один из этих типов наследуется
IEquatable<>
, а не другой?В теории, есть только один разумный способ сравнения двух экземпляров любого типа: они равны , если
X
иY
свойства в обоих случаях одинаковы. В соответствии с этим подходом оба типа должны быть реализованыIEquatable<>
, поскольку маловероятно, что существуют другие значимые способы проведения теста на равенство.Проблема здесь заключается в том, что сравнение чисел с плавающей точкой на равенство может не работать должным образом из-за мелких ошибок округления . Существуют различные методы сравнения чисел с плавающей точкой для почти равенства , каждый из которых имеет определенные преимущества и компромиссы, и вы можете захотеть сами выбрать, какой метод подходит.
Обратите внимание, что на странице, на которую я ссылался (выше), явно указано, что у этого теста на близкое равенство есть некоторые недостатки. Поскольку это
IEqualityComparer<T>
реализация, вы можете просто заменить ее, если она не подходит для ваших целей.источник
IEqualityComparer<T>
реализация должна реализовывать отношение эквивалентности, что подразумевает, что во всех случаях, когда два объекта сравниваются равными третьему, они должны сравниваться равными друг другу. Любой класс, который реализуетIEquatable<T>
или каким- либоIEqualityComparer<T>
образом, противоречащим вышеприведенному, нарушается.IEqualityComparer<String>
который считает «hello» равным «Hello» и «hElLo», должен считать «Hello» и «hElLo» равными друг другу, но для большинства методов сравнения это не будет проблемой.GetHashCode
должен позволить быстро определить, отличаются ли два значения. Правила примерно таковы: (1)GetHashCode
всегда должен выдавать один и тот же хэш-код для одного и того же значения. (2)GetHashCode
должно быть быстро (быстрее, чемEquals
). (3)GetHashCode
не должен быть точным (не таким точным, какEquals
). Это означает, что он может создать один и тот же хэш-код для разных значений. Чем точнее вы можете сделать это, тем лучше, но, вероятно, важнее сохранить его быстрым.Вы уже получили базовое определение того, что они есть . Короче говоря, если вы реализуете
IEquatable<T>
в классеT
,Equals
метод объекта типаT
сообщает вам, равен ли сам объект (проверяемый на равенство) другому экземпляру того же типаT
. Принимая во внимание,IEqualityComparer<T>
что для проверки равенства любых двух экземпляровT
, как правило, выходит за рамки экземпляровT
.Относительно того, для чего они нужны, поначалу сбивает с толку. Из определения должно быть ясно, что следовательно
IEquatable<T>
(определенный в самом классеT
) де-факто должен быть стандарт для представления уникальности его объектов / экземпляров.HashSet<T>
,Dictionary<T, U>
(УчитываяGetHashCode
перекрывается, а),Contains
на иList<T>
т.д. использовать этот. РеализацияIEqualityComparer<T>
наT
не помогает указанных выше общих случаев. Впоследствии, есть небольшая ценность для реализацииIEquatable<T>
на любом другом классе кромеT
. Это:редко имеет смысл.
С другой стороны
как это должно быть сделано.
IEqualityComparer<T>
может быть полезно, когда вам требуется пользовательская проверка равенства, но не как общее правило. Например, в какой-Person
то момент в классе вам может потребоваться проверить равенство двух людей в зависимости от их возраста. В этом случае вы можете сделать:Чтобы проверить их, попробуйте
Точно так же
IEqualityComparer<T>
наT
не имеет смысла.Правда, это работает, но не выглядит хорошо для глаз и побеждает логику.
Обычно то, что вам нужно
IEquatable<T>
. Также в идеале вы можете иметь только один, вIEquatable<T>
то время как несколькоIEqualityComparer<T>
возможно на основе различных критериев.Символы
IEqualityComparer<T>
иIEquatable<T>
точно аналогичныComparer<T>
иIComparable<T>
используются для сравнения, а не для сравнения; хорошая тема здесь, где я написал тот же ответ :)источник
public int GetHashCode(Person obj)
должен вернутьсяobj.GetHashCode()
obj.Age.GetHashCode
. будет редактировать.person.GetHashCode
... почему бы вам это переопределить? - Мы переопределяем, потому что весь смысл вIEqualityComparer
том, чтобы иметь другую реализацию сравнения в соответствии с нашими правилами - правилами, которые мы действительно хорошо знаем.Age
свойстве, поэтому я звонюAge.GetHashCode
. Возраст относится к типуint
, но каким бы ни был тип, это контракт с хеш-кодом в .NETdifferent objects can have equal hash but equal objects cant ever have different hashes
. Это контракт, в который мы можем слепо верить. Конечно, наши пользовательские компараторы также должны придерживаться этого правила. Если когда-либо вызовsomeObject.GetHashCode
ломает вещи, то это проблема с разработчиками типаsomeObject
, это не наша проблема.IEqualityComparer предназначен для использования, когда равенство двух объектов реализуется извне, например, если вы хотите определить компаратор для двух типов, для которых у вас нет источника, или для случаев, когда равенство между двумя вещами имеет смысл только в некотором ограниченном контексте.
IEquatable предназначен для реализации самого объекта (сравниваемого на предмет равенства).
источник
Один сравнивает два
T
с. Другой может сравнивать себя с другимиT
. Обычно вам нужно использовать только один, а не оба.источник