Требование следующее:
если (a.Equals (b)), то a.GetHashCode () == b.GetHashCode ()
Не наоборот.
Вы никогда не должны реализовывать Equals () в терминах GetHashCode (). Для GetHashCode вполне допустимо иметь коллизии, но Equals () не должен возвращать ложных срабатываний.
Я бы предложил эту реализацию:
public override int GetHashCode()
{
return unchecked( this.X * p1 + this.Y * p2 );
}
public override bool Equals(object obj)
{
var other = obj as GreaterThan32Bits;
// you must do the null test after the cast, otherwise the
// function crashes when obj is not a GreaterThan32Bits instance
if (ReferenceEquals(other, null)) return false;
return this.X == other.X && this.Y == other.Y;
}
Где p1 и p2 - большие простые числа. Обычно это приводит к хорошей хеш-функции (несколько коллизий хешей -> Словарь становится эффективным) Если значения X и Y независимы (например, вы не ожидаете много точек на прямой линии, например, X = Y), то даже что-то простое, например X ^ Y
, может быть хорошей хеш-функцией.
Но опять же, вам нужна хорошая хеш-функция, только если вы действительно используете класс в качестве ключей в словаре (или другой хеш-таблице).
На самом деле, вполне нормально всегда возвращать 0 в GetHashCode () и реализовывать только Equals ().
Словарь по-прежнему будет правильно работать с такими объектами, как ключи, он просто будет неэффективным.