Когда объект добавляется в класс .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<Hashable, bool>();
var h = new Hashable();
dict.Add(h, true);
h.PK = 42;
if (!dict.ContainsKey(h)) // returns false, despite same reference
dict.Add(h, false);
}
}