Когда объект добавляется в класс .NET System.Collections.Generic.Dictionary , хэш-код ключа сохраняется внутри и используется для последующих сравнений. Когда хэш-код изменяется после его первоначальной вставки в словарь, он часто становится «недоступным» и может удивить пользователей, когда проверка существования, даже с использованием той же ссылки, возвращает false (пример кода ниже).
GetHashCode в документации говорится:
Метод GetHashCode для объекта должен последовательно возвращать один и тот же хэш-код до тех пор, пока не будет изменено состояние объекта, которое определяет возвращаемое значение метода Equals объекта.
Итак, согласно документы GetHashCode
, хэш-код может измениться всякий раз, когда изменяется состояние, определяющее равенство , однако реализация Dictionary
не поддерживает это.
Текущая реализация словаря .NET нарушена, поскольку она неправильно игнорирует допуски хэш-кода? Должен ли GetHashCode ()
быть основан только на неизменяемых членах? Или есть что-то еще, чтобы разрушить возможную ложную дихотомию?
class Hashable
{
public int PK { get; set; }
public override int GetHashCode()
{
if (PK != 0) return PK.GetHashCode();
return base.GetHashCode();
}
public override bool Equals(object obj)
{
return Equals(obj as Hashable);
}
public virtual bool Equals(Hashable other)
{
if (other == null) return false;
else if (ReferenceEquals(this, other)) return true;
else if (PK != 0 && other.PK != 0) return Equals(PK, other.PK);
return false;
}
public override string ToString()
{
return string.Format("Hashable {0}", PK);
}
}
class Test
{
static void Main(string[] args)
{
var dict = new Dictionary();
var h = new Hashable();
dict.Add(h, true);
h.PK = 42;
if (!dict.ContainsKey(h)) // returns false, despite same reference
dict.Add(h, false);
}
}