Помощники реализации метода Equals (C #) - PullRequest
8 голосов
/ 08 июня 2009

Каждый раз, когда я пишу некоторый класс данных, я обычно трачу столько времени на написание реализации IEquatable.

Последний урок, который я написал, был примерно таким:

public class Polygon
{
    public Point[] Vertices { get; set; }
}

Реализация IEquatable была исчерпывающей. Конечно, C # 3.0 / LINQ очень помогает, но вершины могут быть смещены и / или в обратном порядке, что значительно усложняет метод Equals. После многих модульных тестов и соответствующей реализации я сдался и изменил свое приложение так, чтобы оно принимало только треугольники, для реализации которых в IEquatable требовалось только 11 модульных тестов.

Есть какой-нибудь инструмент или метод, который помогает реализовать Equals и GetHashCode?

Ответы [ 2 ]

8 голосов
/ 08 июня 2009

Я использую ReSharper для генерации членов равенства. При желании он будет реализовывать IEquatable<T>, а также переопределять операторы, если вы этого хотите (чего, конечно, вы никогда не делаете, но в любом случае это круто).

Реализация Equals включает переопределение Object.Equals(Object), а также строго типизированный вариант (который может избежать ненужной проверки типа). Менее типизированная версия вызывает строго типизированную версию после проверки типа. Версия со строгим контролем типов выполняет проверку на равенство ссылок (Object.ReferenceEquals(Object,Object)), а затем сравнивает значения всех полей (ну, только те, которые вы указываете генератору включить).

Что касается GetHashCode, умная факторизация значений поля GetHashCode объединяется (используя unchecked, чтобы избежать исключений переполнения, если вы используете опцию checked компилятора). Каждое из значений поля (кроме первого) перед объединением умножается на простые числа. Вы также можете указать, какие поля никогда не будут иметь значение NULL, и при этом будут отменены любые проверки на NULL.

Вот что вы получите для своего Polygon класса, нажав ALT+Insert и выбрав " Generate Equality Members ":

public class Polygon : IEquatable<Polygon>
{
    public Point[] Vertices { get; set; }

    public bool Equals(Polygon other)
    {
        if (ReferenceEquals(null, other)) return false;
        if (ReferenceEquals(this, other)) return true;
        return Equals(other.Vertices, Vertices);
    }

    public override bool Equals(object obj)
    {
        if (ReferenceEquals(null, obj)) return false;
        if (ReferenceEquals(this, obj)) return true;
        if (obj.GetType() != typeof (Polygon)) return false;
        return Equals((Polygon) obj);
    }

    public override int GetHashCode()
    {
        return (Vertices != null ? Vertices.GetHashCode() : 0);
    }
}

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

В общем, ReSharper выдает много отличного кода всего за несколько секунд. И эта функция находится в моем списке вещей, что делает ReSharper таким замечательным инструментом.

2 голосов
/ 08 июня 2009

Для сравнения двух массивов элементов я использую метод расширения SequenceEqual .

Что касается универсального Equals и GetHashCode, то существует метод, основанный на сериализации, который может работать для вас.

Использование MemoryStream и BinaryFormatter для многократного использования функций GetHashCode и DeepCopy

...