C # GetHashCode вопрос - PullRequest
       39

C # GetHashCode вопрос

8 голосов
/ 05 апреля 2011

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

В случае универсального метода Equals пример может выглядеть следующим образом:

    public bool Equals(Whatever other)
    {
        if (ReferenceEquals(null, other)) return false;
        if (ReferenceEquals(this, other)) return true;

        // Considering that the values can't be 'null' here.
        return other.Id.Equals(Id) || Equals(other.Money, Money) ||
               Equals(other.Code, Code);
    }

Тем не менее, я запутался в создании хорошей реализации GetHashCode для этого случая.

Как это сделать?

Спасибо.

Ответы [ 3 ]

17 голосов
/ 05 апреля 2011

Это ужасное определение Equals, потому что оно не транзитивно.

Рассмотрим

x = { Id = 1, Money = 0.1, Code = "X" }
y = { Id = 1, Money = 0.2, Code = "Y" }
z = { Id = 3, Money = 0.2, Code = "Z" }

Тогда x == y и y == z, но x != z.

Кроме того, мы можем установить, что единственная разумная реализация GetHashCode - это карта констант.

Предположим, что x и y являются различными объектами.Пусть z будет объектом

z = { Id = x.Id, Money = y.Money, Code = "Z" }

Тогда x == z и y == z, чтобы x.GetHashCode() == z.GetHashCode() и y.GetHashCode() == z.GetHashCode() установили, что x.GetHashCode() == y.GetHashCode().Поскольку x и y были произвольными, мы установили, что GetHashCode является константой.

Таким образом, мы показали, что единственно возможная реализация GetHashCode - это

private readonly int constant = 17;
public override int GetHashCode() {
    return constant;
}

Все это вместе дает понять, что вам нужно переосмыслить концепцию, которую вы пытаетесь моделировать, и придумать другое определение Equals.

7 голосов
/ 05 апреля 2011

Я не думаю, что вы должны использовать Равные для этого. Люди имеют очень четкое представление о том, что означает «равенство», и если идентификаторы отличаются, но код или имя совпадают, я бы не стал считать их «равными». Может быть, вам нужен другой метод, например "IsCompatible".

Если вы хотите иметь возможность группировать их, вы можете использовать метод расширения ToLookup () в списке этих объектов, чтобы использовать предикат, который будет вашим методом IsCompatible. Тогда они будут сгруппированы.

6 голосов
/ 05 апреля 2011

Золотое правило: если объекты сравниваются равными, они должны генерировать тот же хеш-код.

Следовательно, соответствующая (но, скажем, нежелательная) реализация будет

public override int GetHashCode()
{
    return 0;
}

Честно говоря, если Id, Name и Code не зависят друг от друга, тогда я не знаю, сможете ли вы добиться большего. Поместить объекты этого типа в хеш-таблицу будет больно.

...