When an object is added to the .NET System.Collections.Generic.Dictionary class the hashcode of the key is stored internally and used for later comparisons. When the hashcode changes after its initial insertion into the dictionary it often becomes "inaccessible" and may surprise its users when an existence check, even using the same reference, returns false (sample code below).
The GetHashCode documentation says:
The GetHashCode method for an object must consistently return the same hash code as long as there is no modification to the object state that determines the return value of the object's Equals method.
So, according to the GetHashCode
docs, the hashcode may change whenever equality-determining state is changed, yet the Dictionary
implementation does not support this.
Is the current .NET dictionary implementation broken in that it incorrectly ignore the hashcode allowances? Should GetHashCode()
only be based on immutable members? Or, is there something else to break a possible false dichotomy?
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);
}
}
Why is it important to override GetHashCode ? It s important to implement both equals and gethashcode, due to collisions, in particular while using dictionaries. if two object returns same hashcode, they are inserted in the dictionary with chaining. While accessing the item equals method is used.
GetHashCode returns a value based on the current instance that is suited for hashing algorithms and data structures such as a hash table. Two objects that are the same type and are equal must return the same hash code to ensure that instances of System.
Every object in . NET has an Equals method and a GetHashCode method. The Equals method is used to compare one object with another object - to see if the two objects are equivalent. The GetHashCode method generates a 32-bit integer representation of the object.
GetHashCode method of the base class, which computes a hash code based on an object's reference; for more information, see RuntimeHelpers. GetHashCode. In other words, two objects for which the ReferenceEquals method returns true have identical hash codes. If value types do not override GetHashCode, the ValueType.
No, you just shouldn't mutate a key (in a material way) after inserting it into a dictionary. This is by design, and the way that every hash table I've ever used works. The docs even specify this:
As long as an object is used as a key in the
Dictionary<TKey, TValue>
, it must not change in any way that affects its hash value. Every key in aDictionary<TKey, TValue>
must be unique according to the dictionary's equality comparer. A key cannot be null, but a value can be, if the value type TValue is a reference type.
So it's only going to surprise users who don't read documentation :)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With