The two interfaces, IComparable and IComparer sound a bit confusing. They both are doing the same thing to some extent, compare the objects in a collection and sorts the elements in a list. So I was confused, when to use IComparable and when to use Icomparer? After some amount of google, I found out that although they are doing the same thing, there are different scenarios where they can be useful. Let’s consider a generic list of integers.
List<int> liInt = new List<int>(); liInt.Add(2); liInt.Add(5); liInt.Add(3);
As we know threre is a built-in sort method by which we can sort the list. So when we call liInt.Sort(), it will sort the elements in the following order:
The output will be:
2
3
5
So Sort() function works perfectly for the collection of built-in type. But how about the custom type list?
Let’s say we have a class called Employee which is defined as follow.
class Employee { public int EmployeeID { get; set; } public string FirstName { get; set; } public string LastName { get; set; } public int yearofExperience { get; set; } public int DesignationRank { get; set; }
public Employee(int empID, string fName, string lName, int yof, int desRank) { EmployeeID = empID; FirstName = fName; LastName = lName; yearofExperience = yof; DesignationRank = desRank; }
}
Suppose we created an employee collection as follow. List<Employee> liEmployee = new List<Employee>(); liEmployee.Add(new Employee(612, “Madhusmita”, “Rout”, 3, 3)); liEmployee.Add(new Employee(314, “soumyashree”, “Mishra”, 5, 1)); liEmployee.Add(new Employee(16, “Anand”, “Keshari”, 12, 2));
Let’s say now we want to sort Employee collection by calling the default sort method, what will happen?
When we call the liEmployee.Sort() method, suprisingly it will generate the exception “Failed to compare the elements in the array” with inner exception “at least one object must implement Icomparable”.
The reason of exception is clear hear, as there is not clearly mentioned on what basis the employee collection should be sorted i.e. on name, year of experience, on the basis of employee id or on designation rank. So .Net framework fails to sort the employee collection.
So to allow the collection of employee objects to be sorted by default we need to implement ICopmareble interface and its CompareTo() method.So we need to enhance the Employee class as mentioned below.
//Implement the IComparable<T> interface
class Employee:IComparable<Employee> { public int EmployeeID { get; set; } public string FirstName { get; set; } public string LastName { get; set; } public int yearofExperience { get; set; } public int DesignationRank { get; set; }
public Employee(int empID, string fName, string lName, int yof, int desRank) { EmployeeID = empID; FirstName = fName; LastName = lName; yearofExperience = yof; DesignationRank = desRank; }
//Implement the CompateTo method public int CompareTo(Employee other) { if (this.EmployeeID > other.EmployeeID) { return 1; } else if (this.EmployeeID < other.EmployeeID) { return -1; } else { return 0; } }
}
So now after implementing the IComparable interface and its CompareTo() method list will be sorted the employee collection without fail.
Now when we call liEmployee.Sort() it will sort the Employee collection on the basis of employee id.
foreach (Employee emp in liEmployee) { Debug.WriteLine(emp.FirstName + “” + emp.LastName); }
|
The output will be: Anand Keshri Soumyashree Mishra Madhusmita Rout
But let’s say in some context, we want to sort the employees by their year of experience then what we need to do? We can modify the CompareTo() method to compare the employee object by YearofExperience property. So should we modify the CompareTo() method? What if tomorrow we need to sort the employees buy their name or designation rank? Will it be ideal like changing the ComapreTo() method every now and then as per our requirement?
Of course, the answer is no. So to overcome this situation .Net framework provides another interface called Icomparer by which we can compare the custom object by any numbers of fields as per our requirement. We can achieve this by creating a separate class which implements the Icomparer interface and its Compare() method.
So let’s say we want to sort the employees by their YearofExperience. Then we have to create a class as follow.
class EmployeeComparerByExperience: IComparer<Employee> { //Implement the compare method
//which compares one employee instance with other
//instance w.r.t to the YearofExperience property public int Compare(Employee x, Employee y) { if (x.yearofExperience > y.yearofExperience) { return 1; } else if (x.yearofExperience < y.yearofExperience) { return -1; } else { return 0; } } }
So now while calling the Sort() method, we just need to pass one instance of EmployeeComparerByExperience class and the employee collection will be sorted by YearOfExperience.
For example: liEmployee.Sort(new EmployeeComparerByExperience());
foreach (Employee emp in liEmployee) { Debug.WriteLine(emp.FirstName + “” + emp.LastName); }
Output: Madhusmita Rout Soumyashree Mishra Anand Keshari
Again, if in some other context we need to sort the employees by their FirstName.
Simply we can create another class which will implement the IComparer interface and compare the employee instance by their name and will pass this class instance to the built-in sort method.
Code to compare the employee by their FirstName
class EmloyeeComparerByName:IComparer<Employee> { //Compare the employee instances by their first name public int Compare(Employee x, Employee y) { if ( x.FirstName.CompareTo(y.FirstName) > 0) { return 1; } else if (x.FirstName.CompareTo(y.FirstName) < 0) { return -1; } else { return 0; } } }
//Code to call the sort method to sort the employee list by their first nameliEmployee.Sort(new EmloyeeComparerByName()); foreach (Employee emp in liEmployee) { Debug.WriteLine(emp.FirstName + “” + emp.LastName); }
Output: Anand Keshari Madhusmita Rout Soumyashree Mishra
So just as summary, we can say that Icomparable can be used to provide default compare and sort facilitiy for custom object whereas IComparer can be used to compare and sort the custom object by numerous fields as per our requirement.
|