Sunday, 10 February 2013

C# Part 2: When are objects the same? Exploration of Equals, GetHashCode and IEquatable

Following on from the previous post which looked at the Equals method overridden from System.Object I will now look at using the alternative version of Equals. So far we have a class Employee which looks like this
public class Employee 
{
    private string employeeName;
    private int employeeNumber;

    public Employee(string employeeName, int employeeN
    {
        this.employeeName = employeeName;
        this.employeeNumber = employeeNumber;
    }

    public override bool Equals(object obj)
    {
        if (obj == null)
            return false;

        Employee other = obj as Employee;
        if (other == null)
            return false;

        if (this.employeeNumber == other.employeeNumbe
            return true;
        else
            return false;
    }

    public bool Equals(Employee obj)
    {
        if (obj == null)
            return false;

        if (this.employeeNumber == obj.employeeNumber)
            return true;
        else
            return false;
    }
}
We wrote some tests, the ones we are interested in this post are
[TestMethod]
public void RhonaIsRhondaTest()
{
    Assert.AreEqual(rhona, rhonda);
}

[TestMethod]
public void RhonaIsRhondaUsingEqualsTest()
{
    Assert.IsTrue(rhona.Equals(rhonda));
}
Both methods pass. However, the first test (using Assert.AreEqual) will execute the Equals method with an object as parameter - the one that overrides the virtual method in System.Object.

In our next test we are going to put two of our employees into a List (andrew and rhonda) and then see if rhona is in the list? Which it should be?
[TestMethod]
public void ContainsInListTest()
{
    List workers = new List<Employee>();
    workers.Add(andrew);
    workers.Add(rhonda);

    Assert.IsTrue(workers.Contains(rhona));
}
The test passes - but if you then run through the debugger it is calling the Equals method inherited from System.Object. Let us now have our Employee class implement the interface IEquatable (or IEquatable<Employee>). This interface is defined as
public interface IEquatable<T>
{
    bool Equals(T other);
}
So the method we have created for Equals(Employee obj) matches this signature. Check the three tests above still pass. The only test that has changed is the call to ContainsTo in the list - which now calls the method as defined by IEquatable. This interface is used by generic collections (such as List).

The next post will look at GetHashCode() and using a HashSet<T>.

No comments:

Post a Comment