All four interfaces IComparable, IComparable<T>, IComparer and IComparer<T> provide comparision functionality to a C# class.
- A class that implements IComparable or IComparable<<T> is comparable itself, it means that an object of that type can compare to another object directly.
- A class that implements IComparer or IComparer<T> is a comparer, it means that an object of that type provides comparision functionality to a set of target objects which either have no comparison ability interally, or the comparison ability provides by themself is not one you want to.
In general, it is preferable to implement the generic interface System.IComparable<T> and System.IComparer<T> rather than the interface System.IComparable and System.IComparer. This is because the generic versions are much safer than the non-generic version by providing a generalized comparison method that a value type or class implements to create a type-specific comparison method for ordering instances.
Talking about whether a class should implements the IComparable or IComparable<<T> interface, or rather than creating a comparer class that implements the IComparer or IComparer<T>, it is determined by whether the the to-be-implemented comparision ability is intrinsic to the class or is only meaningful only in a specific context:
- If the comparision ability is intrinsic to the class, then it is prefer to implement the the IComparable or IComparable<T> interface;
- If the comparision ability is only meaningful only in a specific context, then it is prefer to creating a comparer class that implements the IComparer or IComparer<T> and provides comparision service to the target class.
The followng C# example dmonostrates how to apply the above guidlines to your code.
Employee Class
The following Employee class defines type of empolyee which has four field id, name, age and salary. it also implemnts IComparable<Employee> which makes object of this type is comparable based on its identity.
public class Employee : System.IComparable<Employee>
{
private string _id;
private string _name;
private int _age;
private double _salary;
public string ID
{
get
{
return this._id;
}
}
public string Name
{
get
{
return this._name;
}
}
public int Age
{
get
{
return this._age;
}
}
public double Salary
{
get
{
return this._salary;
}
}
public Employee(string id, string name, int age, double salary)
{
this._id = id;
this._name = name;
this._age = age;
this._salary = salary;
}
public override string ToString()
{
return string.Format("[ID: {0}, Name: {1}, Age: {2}, Salary: {3}]", this._id, this._name, this._age, this._salary);
}
#region IComparable<Employee> Members
int IComparable<Employee>.CompareTo(Employee other)
{
return this.ID.CompareTo(other.ID);
}
#endregion
}
EmployeeNameComparer Class
The following EmployeeNameComparer class creates a comparer based on the name comparision. In case you want to compare two employees based on their name rather than their identity, this class is used for this purpose.
public class EmployeeNameComparer : IComparer<Employee>
{
#region IComparer<Employee> Members
int IComparer<Employee>.Compare(Employee x, Employee y)
{
return x.Name.CompareTo(y.Name);
}
#endregion
}
EmployeeAgeComparer Class
The following EmployeeAgeComparer class creates a comparer based on the age comparision. In case you want to compare two employees based on their age rather than their identity, this class is used for this purpose.
public class EmployeeAgeComparer : IComparer<Employee>
{
#region IComparer<Employee> Members
int IComparer<Employee>.Compare(Employee x, Employee y)
{
int rtn = 0;
if (x.Age < y.Age)
{
rtn = -1;
}
else if (x.Age > y.Age)
{
rtn = 1;
}
return rtn;
}
#endregion
}
Main Program
The follwing main method demonostrates three different scenarios where use different comparision abilities.
class Program
{
static void Main(string[] args)
{
List<Employee> employeeList = new List<Employee>();
employeeList.Add(new Employee("100", "Derrel Brill", 22, 53000));
employeeList.Add(new Employee("300", "Dave Gate", 30, 60000));
employeeList.Add(new Employee("200", "Jimmy Renaud", 55, 80000));
//Sorting argorithm is provided internally by Employee class
Console.WriteLine("Sorted By ID");
employeeList.Sort();
foreach (Employee e in employeeList)
{
Console.WriteLine(e.ToString());
}
Console.WriteLine(Environment.NewLine);
//Sorting argorithm is provided externally
//by EmployeeNameComparer class
Console.WriteLine("Sorting By Name");
employeeList.Sort(new EmployeeNameComparer());
foreach (Employee e in employeeList)
{
Console.WriteLine(e.ToString());
}
Console.WriteLine(Environment.NewLine);
//Sorting argorithm is provided externally
//by EmployeeAgeComparer class
Console.WriteLine("Sorting By Age");
employeeList.Sort(new EmployeeAgeComparer());
foreach (Employee e in employeeList)
{
Console.WriteLine(e.ToString());
}
Console.ReadLine();
}
}