В чем разница между IEqualityComparer и IEquatable?



Я хочу понять сценарии, где IEqualityComparer<T> и IEquatable<T> должен быть использован.
Документация MSDN для обоих выглядит очень похоже.

765   5  

5 ответов:

IEqualityComparer<T> - это интерфейс для объекта, который выполняет сравнение двух объектов типа T.

IEquatable<T> для объекта типа T чтобы он мог сравнить себя с другим.

при использовании IEquatable<T> или IEqualityComparer<T>, можно было бы спросить:

есть ли предпочтительный способ тестирования двух экземпляров T для равенства, или есть несколько одинаково действительных способов?

  • если есть только один способ тестирования двух экземпляров T для равенства, или если один из нескольких методов является предпочтительным, то IEquatable<T> был бы правильный выбор: этот интерфейс предполагается быть реализованным только с помощью T сам, так что один экземпляр T имеет внутреннее знание о том, как сравнить себя с другим экземпляром T.

  • С другой стороны, если есть несколько одинаково разумные способы сравнения двух T s для равенства,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 on List<T> и т. д. воспользоваться этим. Реализация IEqualityComparer<T> on T не помогает в вышеупомянутых общих случаях. Впоследствии, есть небольшое значение для реализации 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> on T не имеет смысла.

class Person : IEqualityComparer<Person>

правда это работает, но не выглядит хорошо для глаз и побеждает логику.

обычно то, что вам нужно-это IEquatable<T>. Также В идеале вы можете иметь только один IEquatable<T> в то время как несколько IEqualityComparer<T> возможна на основе различных критериев.

The IEqualityComparer<T> и IEquatable<T> точно аналогичны Comparer<T> и IComparable<T> которые используются для сравнения вместо того, чтобы приравнивать; хорошая нить здесь где я написал тот же ответ:)

IEqualityComparer используется, когда равенство двух объектов реализуется извне, например, если вы хотите определить компаратор для двух типов, для которых у вас не было источника, или для случаев, когда равенство между двумя вещами имеет смысл только в некотором ограниченном контексте.

IEquatable для самого объекта (тот, который сравнивается для равенства) для реализации.

сравнить два Tы. Другой может сравнить себя с другими Ts. Как правило, вам нужно будет использовать только один в то время, а не оба.

Comments

    Ничего не найдено.