Read the syntax
IComparable<T>.CompareTo defines a type’s default order: negative, zero and positive results mean before, equal and after. List<T>.Sort uses that order when no comparer is supplied.
IComparer<T> supplies a separate ordering, while a Comparison<T> lambda is useful for a one-off sort. Comparers must be consistent; handle nulls explicitly if null values are possible.
Syntax
class X : IComparable<X> { public int CompareTo(X other) { } }Examples
Implementing IComparable
Defining a class's single natural ordering.
List<Student> students = new List<Student>
{
new Student("John", 85),
new Student("Zain", 92),
new Student("Jamal", 78)
};
students.Sort(); // uses CompareTo() automatically
Console.WriteLine(string.Join(", ", students)); // Jamal(78), John(85), Zain(92)
public class Student : IComparable<Student>
{
public string Name;
public int Grade;
public Student(string name, int grade) { Name = name; Grade = grade; }
public int CompareTo(Student? other) => other is null ? 1 : Grade.CompareTo(other.Grade);
public override string ToString() => $"{Name}({Grade})";
}- Defining a class's single natural ordering.
- IComparable<T>.CompareTo defines a type’s default order: negative, zero and positive results mean before, equal and after. List<T>.Sort uses that order when no comparer is supplied.
- Student.CompareTo compares grades, so Sort arranges the students by 78, 85 and 92. The resulting display is Jamal, John, Zain with those grades.
Using a Custom Comparer
An IComparer<T> lets you sort the same objects in a different way without changing the class.
List<Student> students = new List<Student>
{
new Student("Zain", 92),
new Student("John", 85)
};
students.Sort(new ByNameComparer());
Console.WriteLine(string.Join(", ", students)); // John(85), Zain(92)
record Student(string Name, int Grade)
{
public override string ToString() => $"{Name}({Grade})";
}
public class ByNameComparer : IComparer<Student>
{
public int Compare(Student? x, Student? y) => string.Compare(x?.Name, y?.Name);
}- An IComparer<T> lets you sort the same objects in a different way without changing the class.
- IComparable<T>.CompareTo defines a type’s default order: negative, zero and positive results mean before, equal and after. List<T>.Sort uses that order when no comparer is supplied.
- ByNameComparer compares Name rather than Grade. Sorting a list containing Zain and John places John first; this snippet also needs the Student type defined in the same project.
Sorting with a Lambda via Comparison<T>
For quick one-off custom sorts, a lambda is often simpler than a full IComparer<T> class.
List<Student> students = new List<Student>
{
new Student("Zain", 92),
new Student("John", 85),
new Student("Jamal", 78)
};
students.Sort((a, b) => b.Grade.CompareTo(a.Grade)); // descending by grade
Console.WriteLine(string.Join(", ", students)); // Zain(92), John(85), Jamal(78)
record Student(string Name, int Grade)
{
public override string ToString() => $"{Name}({Grade})";
}- For quick one-off custom sorts, a lambda is often simpler than a full IComparer<T> class.
- IComparable<T>.CompareTo defines a type’s default order: negative, zero and positive results mean before, equal and after. List<T>.Sort uses that order when no comparer is supplied.
- The lambda compares b.Grade with a.Grade to reverse grade order. It prints Zain, John, Jamal; this snippet also relies on the Student definition.
Best practices
- Implement IComparable<T> when a class has one obvious, natural ordering (like numbers by value, or dates chronologically)
- Write a separate IComparer<T> class (or use a lambda) when you need multiple different orderings, or cannot modify the class being sorted
- Use a lambda passed to Sort()/OrderBy() for simple, one-off custom orderings instead of writing a full IComparer<T> class
- Handle null carefully in CompareTo()/Compare() implementations - a naive call can throw a NullReferenceException on unexpected null input
Runtime & versions
.NET runtime. Feature availability depends on the language and runtime version used by your project; consult the official reference below.
C# language reference