views:

2137

answers:

5

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?

+12  A: 

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.

Justice
+12  A: 

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.

Andrew Hare
IComparer<T> also allows you to have a class for each type of sort you want. Example; PersonLastFirstNameComparer, PersonFirstLastNameComparer, or PersonAgeComparer.
eschneider
+1  A: 

IComparable says an object can be compared with another. IComparer is an object that can compare any two items.

Neil Barnwell
+2  A: 

As others have said, they don't do the same thing.

In any case, these days I tend not to use IComparer. Why would I? Its responsibility (an external entity used to compare two objects) can be handled much cleaner with a lambda expression, similar to how most of LINQ's methods work. Write a quick lambda which takes the objects to compare as arguments, and returns a bool. And if the object defines its own intrinsic compare operation, it can implement IComparable instead.

jalf
-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.
Joe
And when that is what you need, you return an int (or better still, an enum) instead. Is that really a big deal?
jalf
You can even return a bool, since less than is the only operation you need in order to sort a sequence.
jalf
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.
oɔɯǝɹ
+1  A: 

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.

Mr. Bungle