Не работает ли словарь или GetHashCode () должен основываться только на неизменяемых членах?

Когда объект добавляется в класс .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);
    }
}

12
задан Kaleb Pederson 1 February 2011 в 22:57
поделиться