GetHashCode Равная реализация для класса в C#

У меня есть класс Person, для которого я должен переопределить метод Equals и GetHashCode. Два объекта лица равны, если Имя соответствует ИЛИ, если Электронное письмо соответствует. Какой хороший способ сделать это с помощью довольно эффективной хэш-функции?

class Person
{
    string Name
    string Email

    public override Equals(object obj)
    {
        if (ReferenceEquals(obj, null))
            return false;
        if (ReferenceEquals(this, obj))
            return true;
        if (obj is Person)
        {
            Person person = (Person)obj;
            return
                (this.Name == person.Name)
                || (this.Email == person.Email);
        }
        return false;
    }

    public override GetHashCode()
    {
        // What's a good way to implement?
    }
}

4 ответа

Решение

Вы не можете, правда. Ну, не считая возвращения постоянного значения.

Посмотрите на это так... все люди с электронной почтой "х" должны иметь одинаковый хэш-код, потому что они равны. И все люди с именем "y" должны иметь одинаковый хеш-код, и так далее:

Name    Email    Hash
  n1       e1      h1
  n2       e1      h1 (because emails are equal
  n2       e2      h1 (because names are equal to previous)

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

Я знаю, что это не отвечает на ваш вопрос, но ваш подход неверен. Ожидается, что если a == b и b == c, то из этого обязательно следует, что a == c.

Person a:
    name: mike
    email: someone@website.com

Person b:
    name: steve
    email: someone@website.com

Person c:
    name: steve
    email: steve@website.com

В этом примере a == b и b == c, но a!= C. Это неправильное поведение. Если вы хотите реализовать это поведение, вполне нормально иметь метод, отличный от Equals, который выполняет это сравнение, но не равен.

См. http://msdn.microsoft.com/en-us/library/ms173147%28VS.80%29.aspx.

Как сказал Алекс, это больше связано с бизнес-правилами, и я бы не стал использовать Equals для этой цели. Я хотел бы иметь другой метод, который имеет реализацию у вас в методе Equals.

Конечно, Алекс упоминает хэш Name+email, но это не сработает и для вас, так как Джон указал, что это не то, что вы можете сделать, учитывая ваши бизнес-правила.

Есть способ, которым вы можете делать то, что вы пытаетесь сделать.

Допустим, у вас есть Enum, который вы определили так

public enum MatchedOn { None, Name, Email }

Затем извлеките реализацию вашего метода Equals в другой метод, чтобы вы вызывали его из метода Equals. В этом новом методе установите enum равным Name, если имена равны, или Email, если электронные письма равны, или None, если ни то, ни другое.

Затем в вашей реализации GetHashCode вы также можете вызвать этот новый метод, а затем вернуть хешированный код, основанный на имени или электронной почте или их комбинации.

Я надеюсь, что в этом есть смысл.

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