Помощники реализации метода равных (C#)

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

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

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

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

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

2 ответа

Решение

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

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

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

Вот что вы получаете за свой Polygon класс нажатием ALT+Insert затем выберите "Создать членов равенства":

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 таким удивительным инструментом.

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

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

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

Другие вопросы по тегам