IComparable и IComparer.

И тот и другой интерфейс были созданы для сравнения элементов. При этом оба почему-то имеют право на существование.

Поясните раз и навсегда, когда стоит выбирать один, а когда другой, и есть ли какая-то разница между ними?

По сути интерфейсы идентичны. И там и там есть метод сравнения, который работает по одной схеме : сравнивает элементы путём вычитания одного из другого. Если результат отрицательный - значит элемент слева меньше, если положительный - справа меньше, если равно, то, соответственно, оба элемента равны.

Есть между ними разница.

IComparable предоставляет один единственный метод CompareTo. Этот метод сравнивает ТЕКУЩИЙ объект с аргументом.

IComparer предоставляет метод Compare, который принимает как аргументы 2 объекта другого типа.

Реализация IComparable:

class User : IComparable
    {
        public int Age { get; set; }
        public string Name { get; set; }
        public string Surname { get; set; }
    public User() { }
    public User(int age, string name, string surname)
    {
        Age = age;
        Name = name;
        Surname = surname;
    }

    public int CompareTo(User user)
    {
        return Age - user.Age;
    }
}</pre>

Реализация IComparer:

class User : IComparer
    {
        public int Age { get; set; }
        public string Name { get; set; }
        public string Surname { get; set; }
    public User() { }
    public User(int age, string name, string surname)
    {
        Age = age;
        Name = name;
        Surname = surname;
    }

    public int Compare(User user1, User user2)
    {
        return user1.Age - user2.Age;
    }
}</pre>