Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Talk about System.Object Equals and GetHashcode

0.00/5 (No votes)
14 Mar 2013 1  
If two objects are equal, they would better have the same HashCode.

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 int GetHashCode()
    //{
    //    return Convert.ToInt32(id.Substring(1));
    //}

    /// <summary>
    /// If Id is the same,then Equals
    /// </summary>
    /// <param name="obj"></param>
    /// <returns></returns>
    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()
{
    //create a 100 items hashtable with HashCodeWalkthrough obj as the key
    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.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here