C#

IEqualityComparer Interface

Today I will explain an important collection interface in C# known as the IEqualityComparer Interface. In fact, in C#, we have both the Generic as well as non-generic interface. However, the non-generic interface is not type-safe. What’s more, the generic interface allows us to provide our own definition for equality comparison for the specific user-defined types.

Equality Comparison in Dictionary Collection

Whenever we need to compare two objects for equality using the Equals() method, we can use an implementation of the IEqualityComparer interface. For instance, the generic collection Dictionary requires that the keys must be unique. As a result, whenever you add a key-value pair to an instance of the Dictionary, it will check whether the key is already there or not. Consequently, adding duplicate key results in a run-time error and an exception will be thrown. To clarify this concept look at the following examples.

User-Defined Type as the Key of Dictionary

In order to understand the benefit of the IEqualityComparer interface in creating the keys of a Dictionary, we create a class A that forms the key of the Dictionary as shown below.

using System;
using System.Collections.Generic;
namespace DictionaryExamples2
{
    class A
    {
        public string S { get; set; }
        public override string ToString()
        {
            return $"S = {S}";
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            //Creating Dictionary without IEqualityComparer
            Dictionary<A, int> d1 = new Dictionary<A, int>();
            d1.Add(new A { S = "a" }, 1);
            d1.Add(new A { S = "a" }, 1);

            
            A ob1 = new A { S = "b" };
            d1.Add(ob1, 2);

            foreach (KeyValuePair<A, int> k in d1)
                Console.WriteLine($"Key = {k.Key}, Value = {k.Value}");

            d1.Add(ob1, 2);

        }
    }
}

As can be seen, the two different objects have been added as the keys but an attempt to add the same object as the key resulted in an exception. Hence, it is possible to have two different objects as the keys but the content of the objects is never checked.

Output

Using an Object as the Key of a Dictionary
Using an Object as the Key of a Dictionary

In order to distinguish on the basis of values of the fields of the objects, we need to implement the IEqualityComparer interface and define the Equals() method. As shown below, we compare the value of the field S in the Equals() method.

class comp: IEqualityComparer<A>
    {
        bool IEqualityComparer<A>.Equals(A x, A y)
        {
            return x.S.Equals(y.S);
        }
        int IEqualityComparer<A>.GetHashCode(A obj)
        {
            Random r = new Random(12998);
            return r.Next(12999, 3987878);
        }
    }

Further, we create an instance of class comp and pass it as a parameter to the constructor of the Dictionary as shown in the following code.

comp c = new comp();
            Dictionary<A, int> d2 = new Dictionary<A, int>(c);
            d2.Add(new A { S = "a" }, 1);
            d2.Add(new A { S = "a" }, 1);

            
            foreach (KeyValuePair<A, int> k in d2)
                Console.WriteLine($"Key = {k.Key}, Value = {k.Value}");

As shown in the following output, adding another object as a key with the same value of the field S results in an exception.

Output

Implementing Equals() Method
Implementing Equals() Method

Methods of IEqualityInterface

Basically, this interface declares two methods – Equals() and GetHashCode(). Further, the Equals() method performs the customized equality comparison and the GetHashCode() method returns a hashcode for an object.

Thereafter, let us create a Dictionary with the keys as the objects of the Employee class as shown below and the equality comparison is done on the basis of the salary field. Therefore, any attempt to add key-value pair where the salary field has the same value will result in an exception.

using System;
using System.Collections.Generic;
namespace GenericIEqualityComparerExample
{
       class MyEqualityComparer : IEqualityComparer<Employee>
       {
            bool IEqualityComparer<Employee>.Equals(Employee x, Employee y)
            {
                if (x.salary == y.salary)
                {
                    return true;
                }

                return false;
            }
            int IEqualityComparer<Employee>.GetHashCode(Employee x)
            {
                int i = x.salary;
                double d = Math.Sqrt(i * i + i * i * i);
                d = Math.Pow(d, 1.6);
                int j = (int)d;
                return j;
            }
        }
        class Employee
        {
            public string Name { get; set; }
            public int salary { get; set; }
            public override string ToString()
            {
                return $"Employee Name: {Name}, Salary: {salary}";
            }
        }
        class Program
        {
            static void Main(string[] args)
            {
                MyEqualityComparer c = new MyEqualityComparer();
                Dictionary<Employee, int> d1= new Dictionary<Employee, int>(c);

                Employee[] arr = new Employee[]
                {
                new Employee{Name="A", salary=10000 },
                new Employee { Name = "B", salary = 12000 },
                new Employee { Name = "C", salary = 78000 },
                new Employee { Name = "D", salary = 30000 },
                new Employee { Name = "E", salary = 15000 },
                new Employee { Name = "F", salary = 14000 },
                new Employee { Name = "G", salary = 90000 }
                };

                for (int i = 0; i < arr.Length; i++)
                {
                    d1.Add(arr[i], i + 1);
                }
              //  Employee ob = new Employee { Name = "X", salary = 14000 };
              //  d1.Add(ob, 10);
                //Display all employees...
                foreach (KeyValuePair<Employee, int> ob1 in d1)
                {
                    Console.WriteLine($"Key: {ob1.Key}, HashCode: {ob1.Key.GetHashCode()}");
                    Console.WriteLine($"Value: {ob1.Value}");
            }


            }
        }
    }

Output

Demonstrating IEqualityComparer Interface
Demonstrating IEqualityComparer Interface

Applications of IEqualityComparer Interface

Generally, we implement this interface when we need to provide our own definition of the Equals() method. Specifically, when we need to work with user-defined types as elements of different collections, then we need to provide a custom implementation of the Equals() method so that we can compare the contents of the objects rather than the objects themselves. Therefore, we use it in LINQ (Distinct() method), Lists, Dictionaries, and in several other collections.

Summary

In this article, the IEqualityComparer Interface is discussed in detail. Also, the examples of its implementation in creating the generic dictionary are provided. Further, the methods Equals() and GetHashCode() are also discussed.


Related Topics

A Beginner’s Tutorial on WPF in C#

Everything about Tuples in C# and When to Use?

Linear Search and Binary Search in C#

Creating Jagged Arrays in C#

Learning Indexers in C#

Understanding Method Parameter Modifiers in C#

Object Initializers in C#

Examples of Static Constructors in C#

When should We Use Private Constructors?

C# Practice Questions

C# Basic Examples

Private and Static Constructors in C#

Constructors in C#

C# Arrays

C# Examples

How to Create a C# Console Application

Creating Navigation Window Application Using WPF in C#

LINQ To SQL Examples

Understanding the Concept of Nested Classes in C#

How to Setup a Connection with SQL Server Database in Visual Studio

Examples of Extension Methods in C#

Learning All Class Members in C#

Access Modifiers in C#

C# Root Class – Object

KeyValuePair and its Applications

IEnumerable and IEnumerator Interfaces

Leave a Reply

Your email address will not be published. Required fields are marked *