Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is Equals() being not called for the all objects while adding to collection

I have a type which I am using as key in the IDictionary. The type is as following

public  class Employee
{
    public string Name { get; set; }
    public int ID { get; set; }

    public override bool Equals(object obj)
    {
        Employee emp = obj as Employee;
        if (emp != null)
            return emp.Name.Equals(this.Name);
        return false;
    }

    public override int GetHashCode()
    {
        return this.Name.GetHashCode();
    }
}

Now I have created a dictionary as following in my main as following

 IDictionary<Employee, int> empCollection = new Dictionary<Employee, int>();
        Employee emp1 = new Employee() { Name = "abhi", ID = 1 };
        Employee emp2 = new Employee() { Name = "vikram", ID = 2 };
        Employee emp3 = new Employee() { Name = "vikram", ID = 3 };

        empCollection.Add(emp1, 1);
        empCollection.Add(emp2, 2);
        empCollection.Add(emp3, 3);

Now while debugging I found out that when emp1 is added to the collection only GetHashCode method is called of the key type, after that when emp2 is added to the collection only GetHashCode method is called again but in the case of emp3 both GetHashCode and Equals methods are called.

May be it looks too naive being asking this question but why isn't Equals method not called when eqImp2 object is added to collection. What is happening inside. Please explain.

like image 637
Vikram Avatar asked Feb 20 '13 14:02

Vikram


People also ask

How does equals work in object?

In the first comparison, equals() compares the current object instance with the object that has been passed. If the two objects have the same values, equals() will return true . In the second comparison, equals() checks to see whether the passed object is null, or if it's typed as a different class.

How does equals method work in Java?

The equals() method compares two strings, and returns true if the strings are equal, and false if not.

Does HashMap call equal?

This method is provided by the Object class. You can override this in your class to provide your implementation. HashMap uses equals() to compare the key to whether they are equal or not. If the equals() method return true, they are equal otherwise not equal.


2 Answers

The dictionary and all other similar containers use the hashcode as a quick-and-dirty check: different hashcodes mean that two objects are definitely not equal; identical hashcodes do not mean anything. The documentation of GetHashCode specifies this behavior by saying

If two objects compare as equal, the GetHashCode method for each object must return the same value. However, if two objects do not compare as equal, the GetHashCode methods for the two object do not have to return different values.

Your emp1 and emp2 generate different hashcodes, so the dictionary does not need to run Equals; it already knows they are not equal. On the other hand, emp2 and emp3 generate the same hashcode so the dictionary must call Equals to definitely determine if they are indeed equal, or if the identical hashcode was just the result of chance.

like image 91
Jon Avatar answered Nov 15 '22 22:11

Jon


emp2 and emp3 have the same key. This will cause a "key collision" in the dictionary. It first called GetHashCode() and determined the hash codes were the same. It then ensures they're the same by calling Equals(). The code from Dictionary is:

int num = this.comparer.GetHashCode(key) & 2147483647;
...
if (this.entries[i].hashCode == num && this.comparer.Equals(this.entries[i].key, key))

Obviously, if the hashcodes don't match, it never has to call Equals.

You should get a tool like ILSpy and then you can look at the code and find the answer yourself.

like image 40
Pete Avatar answered Nov 15 '22 21:11

Pete