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
Hashcodes (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.