Difference between IEqualityComparer and IComparer

.NET Framework supplies few useful interfaces for comparing object. Two of them: IEqualityComparer and IComparer might sound bit confusing at first, so in this article I will explain the difference between them and show them in use.

IEqualityComparer

This interface supports the comparison of objects for equality, but what does it truly mean? To understand what equality of two objects is, let's create simple class, so we can compare it later:

public class Student
{
    public string Name { get; set; }
    public string School { get; set; }
 
    public Student(string name, string school)
    {
        this.Name = name;
        this.School = school;
    }
 
    public override string ToString()
    {
        return string.Format("{0} from {1}", this.Name, this.School);
    }
} 

Now let's create new class implementing IEqalityComparer interface. I will use generics because I want to avoid boxing and unboxing from object.

If you would like to read more about advantages of using generics, see this MSDN page.

Before I start, I need to explain how I want to use my comparer. I will use it to select one student, from each school. We can imagine this as some sort of 'School conference' where we need to select one representative from each group.

public class StudentSchoolEqualityComparer : IEqualityComparer<Student>
{
 
    #region IEqualityComparer<Student> Members
 
    public bool Equals(Student x, Student y)
    {
        if (x.School.Equals(y.School))
        {
            return true;
        }
        else
        {
            return false;
        }
    }
 
    public int GetHashCode(Student obj)
    {
        return base.GetHashCode();
    }
 
    #endregion
}

In the example above we can see the only criterion used to check equality of Student object is School property. It means all students even with different names will be considered as equal if their School property is same. We can test our code as follow:

List<Student> Students = new List<Student>();
 
Students.Add(new Student("Jon", "University of Southern California"));
Students.Add(new Student("Philip", "MIT"));
Students.Add(new Student("Mike", "MIT"));
Students.Add(new Student("Adam", "Stanford University"));
Students.Add(new Student("George", "University of Southern California"));
Students.Add(new Student("Jessica", "MIT"));
Students.Add(new Student("Peter", "University of Southern California"));
Students.Add(new Student("Monica", "Stanford University"));
 
Console.WriteLine("All conference students: ");
foreach (Student s in Students)
{
    Console.WriteLine(s);
}
 
List<Student> Representatives = new List<Student>();         
StudentSchoolEqualityComparer comparer = new StudentSchoolEqualityComparer();
 
Representatives = Students.Distinct(comparer).ToList();
 
Console.WriteLine("\nRepresentatives: ");
foreach (Student s in Representatives)
{
    Console.WriteLine(s);
}
Output:
All conference students: Jon from University of Southern California Philip from MIT Mike from MIT Adam from Stanford University George from University of Southern California Jessica from MIT Peter from University of Southern California Monica from Stanford University Representatives: Jon from University of Southern California Mike from MIT Adam from Stanford University

As we can see, even though every Student object is different, our StudentSchoolEqualityComparer class decided to select only three 'unique' entries. Using custom comparer we can easily determine the way when objects are considered as same.

What we should remember about IEqualityComparer interface, is we should use it every time when we want to perform equality comparisons.

IComparer

This interface is slightly different - it not only exposes different methods when implemented, but its main function is to support sorting.

This time our task is to sort students based on the name of their school:

public class SchoolNameComparer : IComparer<Student>
{
 
    #region IComparer<Student> Members
 
    public int Compare(Student x, Student y)
    {
        if (x.School.Equals(y.School))
        {
            return 0;
        }
        else
        {
            return x.School.CompareTo(y.School);
        }
    }
 
    #endregion
}

Note: because we decided to compare Student objects based on the string (School), we could also use built-in class CaseInsensitiveComparer:

public int Compare(Student x, Student y)
{
   return (new CaseInsensitiveComparer()).Compare(x.School, y.School);
}

Now when our Comparer is ready we can use it to sort List<Student> Students:

Console.WriteLine("Original order of the list: ");
foreach (Student s in Students)
{
    Console.WriteLine(s);
}
 
Console.WriteLine("\nSorted using SchoolNameComparer comparer: ");
SchoolNameComparer schoolComparer = new SchoolNameComparer();
Students.Sort(schoolComparer);  
 
foreach (Student s in Students)
{
    Console.WriteLine(s);
}
Output:
Original order of the list: Jon from University of Southern California Philip from MIT Mike from MIT Adam from Stanford University George from University of Southern California Jessica from MIT Peter from University of Southern California Monica from Stanford University Sorted using SchoolNameComparer comparer: Mike from MIT Philip from MIT Jessica from MIT Monica from Stanford University Adam from Stanford University Jon from University of Southern California Peter from University of Southern California George from University of Southern California

As you can see Student objects are correctly sorted based on the value of School property.

Both interfaces are extremely useful when we have to deal with lists and arrays. They allow us to perform sort and select operations based on any criteria we want. Custom EqalityComparers and Comparers can save a lot of time when we must often select and sort our custom data.

Did you like my article? Share it!
Share/Bookmark

Post new comment

The content of this field is kept private and will not be shown publicly.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Allowed HTML tags: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd>
  • Lines and paragraphs break automatically.
  • You can enable syntax highlighting of source code with the following tags: <code>, <blockcode>, <csharp>, <css>, <html>, <javascript>, <vb>, <vbnet>, <xml>. Beside the tag style "<foo>" it is also possible to use "[foo]".

More information about formatting options

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
Image CAPTCHA
Enter the characters (without spaces) shown in the image.
served by y.co.uk