C # проверка на равенство - PullRequest
10 голосов
/ 12 декабря 2010

Каков ваш подход к написанию проверок на равенство для создаваемых вами structs и classes?

1) Требует ли "полная" проверка на равенствостолько стандартного кода (как override Equals, override GetHashCode, универсальный Equals, operator==, operator!=)?

2) Вы явно указываете, что ваши классысмоделировать интерфейс IEquatable<T>?

3) Правильно ли я понимаю, что нет способа автоматически применить Equals переопределения, когда я вызываю что-то вроде a == b и явсегда нужно реализовывать элементы Equals и operator==?

Ответы [ 4 ]

20 голосов
/ 12 декабря 2010

Вы правы, это много стандартного кода, и вам нужно реализовать все по отдельности.

Я бы порекомендовал:

  • Если вы собираетесь реализовать равенство значений вообще, переопределите GetHashCode и Equals(object) - создание перегрузок для == и реализация IEquatable<T> без этого может привести к очень неожиданному поведению
  • Я бы всегда реализовывал IEquatable<T>, если вы переопределяете Equals(object) и GetHashCode
  • Я реже перегружаю оператор ==
  • Правильно реализовать равенство для открытых классов сложно, и все же может привести к неожиданным / нежелательным результатам. Если вам нужно равенство для типов в иерархии, реализуйте IEqualityComparer<T>, выражая интересующее вас сравнение.
  • Равенство для изменяемых типов обычно является плохой идеей, поскольку два объекта могут быть равны, а затем неравны после этого ... если объект видоизменяется (влияющим на равенство) после того, как он используется в качестве ключа в хэш-таблице вы не сможете найти его снова.
  • Некоторые элементы котла немного отличаются для структур ... но, как и Марк, я очень редко пишу свои собственные структуры.

Вот пример реализации:

using System;

public sealed class Foo : IEquatable<Foo>
{
    private readonly string name;
    public string Name { get { return name; } }

    private readonly int value;
    public int Value { get { return value; } }

    public Foo(string name, int value)
    {
        this.name = name;
        this.value = value;
    }

    public override bool Equals(object other)
    {
        return Equals(other as Foo);
    }

    public override int GetHashCode()
    {
        int hash = 17;
        hash = hash * 31 + (name == null ? 0 : name.GetHashCode());
        hash = hash * 31 + value;
        return hash;
    }

    public bool Equals(Foo other)
    {
        if ((object) other == null)
        {
            return false;
        }
        return name == other.name && value == other.value;
    }

    public static bool operator ==(Foo left, Foo right)
    {
        return object.Equals(left, right);
    }

    public static bool operator !=(Foo left, Foo right)
    {
        return !(left == right);
    }
}

И да, это чертовски много шаблонного, очень мало чего меняется между реализациями: (

Реализация == на немного менее эффективна, чем могла бы быть, так как она вызовет Equals(object), который должен выполнить динамическую проверку типа ... но альтернатива еще более варочная панель, вот так:

public static bool operator ==(Foo left, Foo right)
{
    if ((object) left == (object) right)
    {
        return true;
    }

    // "right" being null is covered in left.Equals(right)
    if ((object) left == null)
    {
        return false;
    }
    return left.Equals(right);
}
6 голосов
/ 12 декабря 2010

Я редко делаю что-то особенное для занятий;для большинства обычных объектов справочное равенство работает нормально.

Я еще реже пишу struct;но поскольку структуры представляют значения , обычно уместно обеспечить равенство и т. д. Это обычно включает все;Равно, ==,! = И IEquatable<T> (поскольку в сценариях, использующих EqualityComparer<T>.Default.

, это позволяет избежать бокса. Шаблон обычно не слишком проблематичен, но инструменты IIRC, такие как resharper, могут помочь здесь.

Да, желательно синхронизировать Equals и ==, и это нужно сделать явно.

1 голос
/ 12 декабря 2010

Вам просто нужно реализовать оператор == для a == b.
Поскольку мне нравятся мои данные в словарях, иногда я переопределяю GetHashCode.
Далее я реализую Equals (как не упомянутый стандарт ... это потому, что при использовании обобщений нет ограничений на равенство) и определяю реализацию IEquatableПоскольку я собираюсь сделать это, я мог бы также указать, что мои == и! = Реализации равны.:)

0 голосов
/ 17 декабря 2012

См. Что такое «Лучшая практика» для сравнения двух экземпляров ссылочного типа?

Вы можете избежать кода котельной пластины (надеюсь, что команда C # / VS поможет разработчикам в ихследующая итерация) с помощью фрагмента, вот один из таких ..

...