As the name suggests, IComparable
reads out I'm comparable. IComparable
when defined for T
lets you compare the current instance with another instance of same type. IComparer
reads out I'm a comparer, I compare. IComparer
is used to compare any two instances of T
, typically outside the scope of the instances of T
.
As to what they are for can be confusing at first. From the definition it should be clear that hence IComparable
(defined in the class T
itself) should be the de facto standard to provide the logic for sorting. The default Sort
on List
etc relies on this. Implementing IComparer
on T
doesn't help regular sorting. Subsequently, there is little value for implementing IComparable
on any other class other than T
. This:
class MyClass : IComparable
rarely makes sense.
On the other hand
class T : IComparable
{
public int CompareTo(T other)
{
//....
}
}
is how it should be done.
IComparer
can be useful when you require sorting based on a custom order, but not as a general rule. For instance, in a class of Person
at some point you might require to Sort people based on their age. In that case you can do:
class Person
{
public int Age;
}
class AgeComparer : IComparer
{
public int Compare(Person x, Person y)
{
return x.Age - y.Age;
}
}
Now the AgeComparer
helps in sorting a list based on Age
.
var people = new Person[] { new Person { age = 23 }, new Person(){ age = 22 } };
people.Sort(p, new AgeComparer()); //person with age 22 comes first now.
Similarly IComparer
on T
doesn't make sense.
class Person : IComparer
True this works, but doesn't look good to eyes and defeats logic.
Usually what you need is IComparable
. Also ideally you can have only one IComparable
while multiple IComparer
is possible based on different criteria.
The IComparer
and IComparable
are exactly analogous to IEqualityComparer
and IEquatable
which are used for testing equality rather than comparing/sorting; a good thread here where I wrote the exact same answer :)