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 вы также можете вызвать этот новый метод, а затем вернуть хешированный код, основанный на имени или электронной почте или их комбинации.
Я надеюсь, что в этом есть смысл.