Каково различие между IEquatable и просто переопределяющий Объект. Равняется ()?

Я хочу мой Food класс, чтобы смочь протестировать каждый раз, когда это равно другому экземпляру Food. Я буду позже использовать его против Списка, и я хочу использовать List.Contains() метод. Если я реализую IEquatable<Food> или просто переопределение Object.Equals()? Из MSDN:

Этот метод определяет равенство при помощи компаратора равенства по умолчанию, как определено реализацией объекта IEquatable. Равняется методу для T (тип значений в списке).

Таким образом, мой следующий вопрос: который используют функции/классы платформы.NET Object.Equals()? Я должен использовать его во-первых?

168
задан silkfire 1 August 2017 в 04:32
поделиться

3 ответа

Основная причина - производительность. Когда в .NET 2.0 были представлены дженерики, они смогли добавить кучу изящных классов, таких как List , Dictionary , HashSet и т. Д. Эти структуры интенсивно используют GetHashCode и Equals . Но для типов значений это требовало бокса. IEquatable позволяет структуре реализовать строго типизированный метод Equals , поэтому упаковка не требуется. Таким образом, производительность намного выше при использовании типов значений с универсальными коллекциями.

Ссылочные типы не так сильно выигрывают, но реализация IEquatable позволяет избежать преобразования из System.Object , которое может иметь значение, если он часто вызывается.

Однако, как отмечалось в блоге Джареда Парсона , вы все равно должны реализовать переопределения объектов.

193
ответ дан 23 November 2019 в 20:56
поделиться

Согласно MSDN:

Если вы реализуете IEquatable, вы вы также должны переопределить базовый класс реализации Object.Equals(Object) and GetHashCode так, чтобы их поведение соответствовало с поведением IEquatable.Equals метод. Если вы переопределите Object.Equals(Object), ваша переопределенная реализация также вызывается в вызовах к статическому Equals(System.Object, System.Object) метода вашего класса. Это гарантирует, что все вызовы метода Equals возвращают согласованные результаты.

Таким образом, кажется, что между этими двумя методами нет реальной функциональной разницы, за исключением того, что любой из них может быть вызван в зависимости от того, как используется класс. С точки зрения производительности, лучше использовать общую версию, потому что с ней не связаны штрафы за боксирование/небоксирование.

С точки зрения логики, также лучше реализовать интерфейс. Переопределение объекта не говорит никому о том, что ваш класс действительно эквивалентен. Переопределение может быть просто классом "ничего не делать" или неглубокой реализацией. Использование интерфейса явно говорит: "Эй, эта вещь действительна для проверки равенства!". Это просто лучший дизайн.

45
ответ дан 23 November 2019 в 20:56
поделиться

Расширяя сказанное Джошем практическим примером. +1 к Джошу - я собирался написать то же самое в своем ответе.

public abstract class EntityBase : IEquatable<EntityBase>
{
    public EntityBase() { }

    #region IEquatable<EntityBase> Members

    public bool Equals(EntityBase other)
    {
        //Generic implementation of equality using reflection on derived class instance.
        return true;
    }

    public override bool Equals(object obj)
    {
        return this.Equals(obj as EntityBase);
    }

    #endregion
}

public class Author : EntityBase
{
    public Author() { }
}

public class Book : EntityBase
{
    public Book() { }
}

Таким образом, у меня есть повторно используемый метод Equals(), который работает из коробки для всех моих производных классов.

27
ответ дан 23 November 2019 в 20:56
поделиться
Другие вопросы по тегам:

Похожие вопросы: