Importance of Equals Method in C#

Objective

It's important to understand the concept of Equals() in C# to get the desired output. When I started programming, sometimes when I tried to check whether or not two objects are equal, surprisingly I used to get the wrong output. Then I spent a little time on the concept and finally got to understand why I had reviously gotten the wrong output.

Let's say we have the following two strings:

  1. string first = "Arun";  
  2. string second = "Arun";  
To check the equality we can do either of these:
  1. Console.WriteLine(first == second);  
  2. Console.WriteLine(first.Equals(second));  
If we run both of the cases then we will get output as “true”.



This process is true for all data types like int, double and so on. Now you might ask, where is the problem?

The Problem

The real problem occurs when we do the same operation to check whether two “custom” objects are equal or not. Let's elaborate this with an example. Say, we have an Employee class as follows:
  1. public class Employee  
  2.     {  
  3.         public string Name { getset; }  
  4.         public int Age { getset; }  
  5.         public double Salary { getset; }  
  6.   
  7.         Employee(string name, int age, double sal)  
  8.         {  
  9.             Name = name;  
  10.             Age = age;  
  11.             Salary = sal;  
  12.         }  
  13.   
  14.         public List<Employee> GetEmployees()  
  15.         {  
  16.             var employeeList = new List<Employee>();  
  17.   
  18.             employeeList.Add(new Employee("Arunava", 29, 25000));  
  19.             employeeList.Add(new Employee("Aamir", 56, 50000));  
  20.             employeeList.Add(new Employee("Santanu", 78, 39000));  
  21.             employeeList.Add(new Employee("Bubu", 67, 40000));  
  22.   
  23.             return employeeList;  
  24.         }  
  25.     }  
A simple class with 3 properties, a constructor and one method to get a list of employees. Now let's check our Main method:
  1. static void Main(string[] args)  
  2.         {  
  3.             var employeeList = Employee.GetEmployees();  
  4.   
  5.             var checkEmployee = new Employee("Arunava", 29, 25000);  
  6.             Console.WriteLine(employeeList.Contains(checkEmployee));  
  7.             Console.ReadLine();  
  8.   
  9.         }  
What are we expecting here as output?

The “checkEmployee” is definitely present there in “employeeList”, but we get the output as:



Surprising. Isn't it?

Solution

Nothing is wrong with your assumption. How does the computer (in other words, the complier) know that you meant to determine whether the objects are equal with the Name, Age and Salary are same? What if, somebody says, the objects are equal if their names are the same? Another guy might say, no, I will accept that the objects are equal if the Name and Age are the same. So, C# left it to the user to define the equality condition. And guess what, you can use the Equals() method to define the condition.

Implementing Equals()

There are guidelines to see how to implement the Equals method in MSDN: https://msdn.microsoft.com/en-us/library/ms173147.aspx

Generally, whenever I create a custom class and I know that I need to do an Equality check I implement Equals() and also keep GethashCode() and operator == in sync as well. This is how I implemented my Equality check for the class of this example:
  1. public override bool Equals(object second)  
  2.         {  
  3.             return Equals(second as Employee);  
  4.         }  
  5.   
  6.         public virtual bool Equals(Employee second)  
  7.         {  
  8.             if (second == null) { return false; }  
  9.             if (object.ReferenceEquals(this, second)) { return true; }  
  10.             return ((this.Name == second.Name) && (this.Salary == second.Salary) && (this.Age == second.Age));  
  11.         }  
  12.   
  13.         public override int GetHashCode()  
  14.         {  
  15.             return this.Age;  
  16.         }  
  17.   
  18.         public static bool operator ==(Employee item1, Employee item2)  
  19.         {  
  20.             if (object.ReferenceEquals(item1, item2)) { return true; }  
  21.             if ((object)item1 == null || (object)item2 == null) { return false; }  
  22.             return ((item1.Name == item2.Name) && (item1.Salary == item2.Salary) && (item1.Age == item2.Age));  
  23.         }  
  24.   
  25.         public static bool operator !=(Employee item1, Employee item2)  
  26.         {  
  27.             return ((item1.Name == item2.Name) && (item1.Salary == item2.Salary) && (item1.Age == item2.Age));  
  28.         }  
Conclusion

After implementing this, if we run the same code we get our desired output:
  1. var employeeList = Employee.GetEmployees();  
  2.   
  3. var checkEmployee = new Employee("Arunava", 29, 25000);  
  4. Console.WriteLine(employeeList.Contains(checkEmployee));  
  5. Console.ReadLine();  
Output



So remember, whenever you have a condition to check the Equality between objects, don't forget to correctly implement Equals() and HashCodes(). Why did the Sting at the beginning provide the correct result earlier? Well, those classes have already implemented Equals() and HashCode().

Enjoy coding.