Dot Net For All

Comparing C# types – IComparable or IComparer

How to make best of the interfaces provided by .NET framework for comparison types? In this article I will discuss why to use IComparable or IComparer interfaces or to be more precise difference between IComparable and IComparer. And why do we need to compare types in .NET at first place.Lets’s start checking all the aspects one by one by using C# examples.

Before Comparison you may read about type equality at the below links:

Why do we need Comparison

Comparison allow us to compare variables of same type. This can be further used for sorting the elements in a collection. If a C# class wants to tell the outside world about its comparison capability it needs to implement IComparable. Let’s see an example.

  string[] strArray = new string[] { "orange", "banana", "apple", "pomogranate" };
  Array.Sort(strArray);
  Console.WriteLine(string.Join("\n", strArray));

And the output of the above code will be .

String sort using IComparable

As we can see string knows that how to compare itself and that is why array of strings has been able to sort itself. This innate capability to compare and sort a string is given by the implementation of the IComparable<T> interface for string class.  From the result we can see that it is capability of the string class to itself alphabetically.

Using IComparable in Custom Class

Now suppose I have Student class as shown in the code below. And I want to compare all the students by their name.

  public class Student
  {
      public string Name { get; set; }
  }

  Student[] arrStudent = new Student[] { new Student() { Name = "Vikram" },
            new Student() { Name = "Abhishek" },
            new Student() { Name = "Greg" },
            new Student() { Name = "Thomas" }};

  Array.Sort(arrStudent);

As we run this code we will get the exception “Failed to compare two elements in the array. At least one object must implement IComparable” as shown in the figure below.

IComparable Exception

To provide the default implementation of the comparison for the class so that it can be sorted in a collection we need to implement the IComparable interface. Check the C# code below for changed class with comparison capabilities.

 public class Student:IComparable
 {
      public string Name { get; set; }
      public int CompareTo(object obj)
      {
          Student stuObj = obj as Student;
          if(stuObj != null)
          {
              return this.Name.CompareTo(stuObj.Name);
          }
          return -1;
      }          
  }

And we will get the desired output of all the elements sorted in alphabetically order in the array.

Using the IComparer for the Class

Now suppose after some time a requirement comes where we need to add one more field to the Student class named TotalMarks. And I want my student collection to be sorted by the marks.

Should we make a change to the Student class itself for this new comparison? It’s not a good idea to keep changing the Student class for each and every new comparison and specially in this case where we have already provided a default comparison for the student class which is by name.

For this new sorting requirement we should have a class which implements IComparer<T>. Check the code below

 public class Student:IComparable
        {
            public string Name { get; set; }

            public int TotalMarks { get; set; }

            public int CompareTo(object obj)
            {
                Student stuObj = obj as Student;
                if(stuObj != null)
                {
                    return this.Name.CompareTo(stuObj.Name);
                }

                return -1;
            }          
        }

        public class MarksComparer : IComparer<Student>
        {
            public int Compare(Student x, Student y)
            {
                return x.TotalMarks.CompareTo(y.TotalMarks);
            }
        }

For comparing the Student collection by marks I can use the above comparer class as shown in the code below.

  Array.Sort(arrStudent, new MarksComparer());

As seen in the code above we have written a custom comparer using IComparer which does it’s job perfectly of comparing types. Therefore adhering to Single responsibility principle of SOLID. 

Why comparison is not part of System.Object

Why do you think that Microsoft decided not to include CompareTo method in the System.Object implementation unlike Equals() method. The reason is that it is not mandatory to have each and every object to have comparisons. For example, there are two button of type Button. How do you think that these two button be compared? I think there is no default way by which they can be compared.

Conclusion:

In this article we have seen two ways by which we can make a class to have comparison support for its instances.

Top career enhancing courses you can't miss

My Learning Resource

Excel your system design interview