When to use IComparable<T> Vs. IComparer<T>

31,677

Solution 1

Well they are not quite the same thing as IComparer<T> is implemented on a type that is capable of comparing two different objects while IComparable<T> is implemented on types that are able to compare themselves with other instances of the same type.

I tend to use IComparable<T> for times when I need to know how another instance relates to this instance. IComparer<T> is useful for sorting collections as the IComparer<T> stands outside of the comparison.

Solution 2

Use IComparable<T> when the class has an intrinsic comparison.

Use IComparer<T> when you want a comparison method other than the class' intrinsic comparison, if it has one.

Solution 3

It depends on the entity. For example following for a class like "Student", it will make sense to have IComparable based on Name.

class Student : IComparable 
{
    public string Name { get; set; }
    public int MathScore { get; set; }
    public int EnglishScore { get; set; }

    public int TotalScore 
    {
        get
        {
            return this.MathScore + this.EnglishScore; 
        }
    }

    public int CompareTo(object obj)
    {
        return CompareTo(obj as Student);  
    }

    public int CompareTo(Student other)
    {
        if (other == null)
        {
            return 1;
        }
        return this.Name.CompareTo(other.Name);  
    }
}

But if a teacher 'A' wants to compare students based on MathScore, and teacher 'B' wants to compare students based on EnglishScore. It will be good idea to implement IComparer separately. (More like a strategy pattern)

class CompareByMathScore : IComparer<Student>
{
    public int Compare(Student x, Student y)
    {
        if (x.MathScore > y.MathScore)
          return 1;
        if (x.MathScore < y.MathScore)
          return -1;
        else
          return 0;
    }
}

Solution 4

Simple Explanation via a story

High school basketball. It's a school yard pick for the teams. I want to get the tallest/best/fastest folks on my team. What do I do?

IComparer Interface - Compare two people separate people

  • This allows me to compare any two guys lined up.........that's basically it. Fred vs John..........i throw them into a concrete class which implements the interface. Compare(Fred, John) and it spits out who's better.

What about IComparable? - Compare yourself with someone else

Have you been on FB recently? You see other folks doing cool things: travelling the world, creating inventions, while I'm doing something not quite as cool - well what we are doing is making use of the IComparable interface.

  • We are comparing the current instance (yourself) with another object (someone else) which is of the same type (person).

What about the Comparer Class?

The Comparer class is an abstract base class which implements the IComparer interface. You should derive from this class to have a concrete implementation. anyways, Microsoft recommends that you DO use the Comparer class rather than implement the IComparer interface:

We recommend that you derive from the Comparer class instead of implementing the IComparer interface, because the Comparer class provides an explicit interface implementation of the IComparer.Compare method and the Default property that gets the default comparer for the object.

Summary

  • IComparer - line up two things and compare.
  • IComparable - compare yourself with others on FB.

Hope the stories help you remember.

Solution 5

It all depends on whether your type is mutable or not. You should only implement IComparable on non-mutable types. Note that if you implement IComparable, you must override Equals, along with the ==, !=, < and > operators (see Code Analysis warning CA1036).

Quoting Dave G from this blog post:

But the correct answer is to implement IComparer instead of IComparable if your objects are mutable, and pass an instance of the IComparer to sorting functions when necessary.

Since the IComparer is just a disposable object used for sorting at that point in time, your object can have any mutable semantics you desire. Furthermore, it doesn't require or even suggest using Equals, GetHashCode, or == - you're free to define it in any way you please.

Finally, you can define multiple IComparer's for your type for sorting on different fields or with different rules. This is much more flexible than being stuck with one definition.

In short: Use IComparable for value types and IComparer for reference types.

Share:
31,677

Related videos on Youtube

Micah
Author by

Micah

Updated on July 08, 2022

Comments

  • Micah
    Micah almost 2 years

    I'm trying to figure out which of these interfaces I need to implement. They both essentially do the same thing. When would I use one over the other?

  • Joe
    Joe over 15 years
    -1: returning a bool is not equivalent to IComparer. IComparer returns a value that can be less than zero/zero/greater than zero and is typically used for sorting.
  • josesuero
    josesuero over 15 years
    And when that is what you need, you return an int (or better still, an enum) instead. Is that really a big deal?
  • josesuero
    josesuero over 15 years
    You can even return a bool, since less than is the only operation you need in order to sort a sequence.
  • oɔɯǝɹ
    oɔɯǝɹ over 14 years
    an IComparer implementation only needs to be defined once, if you need to use the sorting logic in more places, then the lambda expression will need to be written more times.
  • Admin
    Admin about 14 years
    IComparer<T> also allows you to have a class for each type of sort you want. Example; PersonLastFirstNameComparer, PersonFirstLastNameComparer, or PersonAgeComparer.
  • jpierson
    jpierson almost 13 years
    oɔɯǝɹ - Then you can store a reference to the delegate that was written as a lambda expression are reuse it as well.
  • amadib
    amadib about 12 years
    Is there an easy way you use to remember them? I tend to have to look it up each time.
  • nawfal
    nawfal over 11 years
    @amadib think IComparable as I'm comparable. which means I can be compared to something else. And read IComparer as I'm a comparer, I simply compare which means I compare some things.
  • Gene S
    Gene S about 8 years
    @newfal You should have put this as an answer. I think it is the best explanation here.
  • Kevman
    Kevman about 7 years
    I like your way to illustrating the key concept. It could be better if you including the Comparer(T) class into this contest. Even it's not including in the question. :)
  • Jan
    Jan over 5 years
    Make the Compare method static for easy of use.