Understanding Equality And Identity In C#

C# has an "Equals" method which can be used to compare two objects. I will try to explain the Equality and Identity concept with examples here.

Example 1

  1. namespace TestEqualityDemo  
  2. {  
  3.     class Program  
  4.     {  
  5.         static void Main(string[] args)  
  6.         {  
  7.             TestEquality test1 = new TestEquality();  
  8.             test1.FirstName = "Tom";  
  9.             test1.FirstName = "Cruise";  
  10.   
  11.             TestEquality test2 = new TestEquality();  
  12.             test2.FirstName = "Tom";  
  13.             test2.FirstName = "Cruise";  
  14.             TestEquality test3 = test2;  
  15.             bool areEqual = test1.Equals(test2);  
  16.             System.Console.WriteLine("Are test1 and test2 are Equal:" + areEqual);  
  17.   
  18.             areEqual = test2.Equals(test3);  
  19.             System.Console.WriteLine("Are test2 and test3 are Equal:" + areEqual);  
  20.             System.Console.ReadLine();  
  21.         }  
  22.     }  
  23.   
  24.     class TestEquality  
  25.     {  
  26.         public string FirstName { getset; }  
  27.         public string LastName { getset; }  
  28.     }  

Output
  1. Are test1 and test2 Equal:False  
  2. Are test2 and test3 Equal:True  
In the above example,
  • Even if test1 and test2 contain the same value for FirstName and LastName, the "Equals" method returns False. That is because default implementation of Equals method does not check for Equality; it checks for Identity. This means test1 and test2 must refer to the exact same object, then only it will return True, otherwise, it will return False.

  • As test2 and test3 are referring to the same object, it returns True. As per the above program we can conclude that default implementation of Equals checks for Identity which means it will return True only if two variables are referring to the same object. 
Then, the question arises how to check for equality in C# ,and the answer for this is to override the default implementation of Equals method.
 
Here is the default implementation of Equals method.
  1. public virtual bool Equals(Object obj)  
  2. {  
  3.     //If both the references points to the same object then only return true  
  4.     if (this == obj)  
  5.     {  
  6.         return true;  
  7.     }  
  8.     return false;  
The following points must be considered to override Equals method,
  1. If the obj argument is null it returns false
  2. If this and obj refers to the same object it returns True. This can improve the performance when comparing values with many fields
  3. If this and obj are referring to different type it returns False, because there is no point in comparing the objects of different type; for example, if we compare a String object with DateTime object because they will not be equal in any situation.
  4. Compare each field of this object with the respective field of obj object.
  5. Finally, call the base class Equals method.
The above are the  best steps to override Equals method for comparison.

Let's implement Equals method for TestEquality class.
  1. namespace TestEqualityDemo  
  2. {  
  3.     class Program  
  4.     {  
  5.         static void Main(string[] args)  
  6.         {  
  7.             TestEquality test1 = new TestEquality();  
  8.             test1.FirstName = "Tom";  
  9.             test1.FirstName = "Cruise";  
  10.   
  11.             TestEquality test2 = new TestEquality();  
  12.             test2.FirstName = "Tom";  
  13.             test2.FirstName = "Cruise";  
  14.   
  15.             TestEquality test4 = new TestEquality();  
  16.             test2.FirstName = "Will";  
  17.             test2.FirstName = "Smith";  
  18.   
  19.             TestEquality test3 = test2;  
  20.             bool areEqual = test1.Equals(test2);  
  21.             System.Console.WriteLine("Are test1 and test2 Equal:" + areEqual);  
  22.   
  23.             areEqual = test2.Equals(test3);  
  24.             System.Console.WriteLine("Are test2 and test3 Equal:" + areEqual);  
  25.             System.Console.ReadLine();  
  26.   
  27.             areEqual = test2.Equals(test4);  
  28.             System.Console.WriteLine("Are test2 and test4 Equal:" + areEqual);  
  29.             System.Console.ReadLine();  
  30.         }  
  31.     }  
  32.   
  33.     class TestEquality  
  34.     {  
  35.         public string FirstName { getset; }  
  36.         public string LastName { getset; }  
  37.   
  38.         public override bool Equals(System.Object obj)  
  39.         {  
  40.             //If the obj argument is null return false  
  41.             if (obj == null)  
  42.                 return false;  
  43.             //If both the references points to the same object then only return true  
  44.             if (this == obj)  
  45.                 return true;  
  46.   
  47.             //If this and obj are referring to different type return false  
  48.             if (this.GetType() != obj.GetType())  
  49.                 return false;  
  50.   
  51.             //Compare each field of this object with respective field of obj object  
  52.             TestEquality test = (TestEquality)obj;  
  53.             if (this.FirstName == test.FirstName &&  
  54.             this.LastName == test.LastName)  
  55.             {  
  56.                 return true;  
  57.             }  
  58.             return false;  
  59.         }  
  60.     }  

Output
  1. Are test1 and test2 Equal:True  
  2. Are test2 and test3 Equal:True  
  3. Are test2 and test4 Equal:False  
In the above program,
  1. All the fields of test1 and test2 are equal so Equals method returns true.
  2. test2 and test3 refers to the same object so it will also return true
  3. In test2 and test4 if values are different for FirstName and LastName it returns false
The following rules must be followed by overridden Equals method,
  1. Equals must be reflexive, that is x.Equals(x) must return true.
  2. Equals must be symmetric, that is x.Equals(y) must return the same value as y.Equals(x)
  3. Equals must be transitive i.e if x.Equals(y) returns true and y.Equals(z) returns true then x.Equals(z) must return true.
If overridden Equals method does not follow the above rules, there are chances that your application will break or give unexpected results.