Introduction
Just a simple example to show why we need to override GetHashCode
if we override
Equals
, just understanding why "if two objects are equal, they would better have
the same HashCode".
Background
In C#, when we create a class, it is automatically inherited from System.Object
, and we
inherit the Equals
and GetHashCode
methods. We can override them, but if we override
Equals
without overriding GetHashCode
, we will get a warning message: "overrides Object.Equals(object o) but does not override Object.GetHashCode()".
Why is Microsoft warning you this? If you don't plan to use your object as a key for hash collections (like
Hashtable
, Dictionary
, etc.), it is OK. Otherwise you will
face a problem.
Using the Code
I define a class and override the Equals
method.
If the Ids are the same, the two objects are equal. In the RunOverEqualsWithoutHashCode
method,
I create a Hashtable
using HashCodeWalkthrough
as key and store 100 items, then
I tried to find the A50, but got nothing.
Then if I override the GetHashCode
method,
I can find the items in the Hashtable
.
class HashCodeWalkthrough
{
public override bool Equals(object obj)
{
if (null == obj) return false;
HashCodeWalkthrough obj2 = obj as HashCodeWalkthrough;
if (obj2 == null) return false;
return this.id.Equals(obj2.Id);
}
#region Properties
string name = string.Empty;
public string Name
{
get { return name; }
set { name = value; }
}
string id = string.Empty;
public string Id
{
get { return id; }
set { id = value; }
}
#endregion
}
private static void RunOverEqualsWithoutHashCode()
{
Hashtable hash = new Hashtable();
for (int i = 0; i < 99; i++)
{
hash.Add(new HashCodeWalkthrough() { Id = "A" + i, Name = "Name" + i },
"Value" + i);
}
HashCodeWalkthrough search50 = new HashCodeWalkthrough() { Id = "A50", Name = "Name50" };
Console.WriteLine(hash.ContainsKey(search50));
Console.WriteLine("Find the 50th in Hashtable");
string value = hash[search50] as string;
Console.WriteLine(value);
}
public override int GetHashCode()
{
return Convert.ToInt32(id.Substring(1));
}
Points of Interest
The trick is that when storing data in a hash collection, it uses the object's
Hashcode
to find a bucket. When getting items, it also uses the key object's Hashcode
to search the bucket.
Although the two key objects Equals (because we override), they have different
Hashcode
s (by default System.Object
returns a unique ID in
the AppDomain for any new object), so when getting, it will find no bucket, so that item
will actually be missing.