Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's the Comparer<T> class for?

Tags:

What purpose does the Comparer<T> class serve if the type that you specify already implements IComparable?

If I specify Comparer.Default, and Customer already implements IComparable, then why would I use the Comparer class?

like image 569
Razor Avatar asked May 16 '10 09:05

Razor


People also ask

What is the Comparer class used for?

Objects Comparer framework provides a mechanism to compare complex objects, and allows us to override comparison rules for specific properties and types.

What is comparer c#?

Objects Comparer is an object-to-object comparer that allows you to compare objects recursively member by member and defines custom comparison rules for certain properties, fields, or types. Objects Comparer can be considered as ready to use a framework or as an idea for similar solutions.

When to use IComparer c#?

The role of IComparer is to provide more comparison mechanisms. For example, you might want to provide ordering of your class on several fields or properties, ascending and descending order on the same field, or both. The IComparer. Compare method requires a tertiary comparison.


2 Answers

Because you need sometimes keep sets/ordered queues ordered by something else then 'natural' order or more then one natural order exists.

For example if you have plane lines you may want to sort it by:

  • Flight number
  • Destination
  • Time
  • Priority (some flights can suffer longer delays then others)
  • ...

Tasks in computer can be scheduled by:

  • User
  • Priority (in scheduler)
  • PID (normal comparation)
  • ...

So even in one application you may need to sort the objects by different properties. You cannot do this by int compareTo(Object) method as it cannot differentatie between contexts. However you can add the context i.e. implement CompareByPriority.

like image 114
Maciej Piechotka Avatar answered Sep 21 '22 12:09

Maciej Piechotka


I think your question is why have a base class that only seems to have one useful method which happens to be the same method you'd implement if you implemented the interface directly. If I understood that correctly I guess you're right that there's not much benefit to deriving from Comparer<T> as opposed to implementing IComparer<T> directly except that the base class provides you with a generic and non-generic implementation with a single overridden method.

But if your question is why have both IComparer<T> and IComparable<T>, then as others have indicated, Comparer<T> allows you to define different ways to perform the comparison. It is an implementation of the Strategy design pattern. A great example of this would be the various StringComparer properties such as StringComparer.Ordinal, StringComparer.OrdinalIgnoreCase, etc. This allows you to sort strings differently under different circumstances which the IComparable<T> interface simply cannot anticipate.

But in addition to being able to re-define the way a comparison is performed, sometimes providing an external comparer is the only way you can do it. For example, the Windows Forms ListView class allows you to specify an IComparer for its sort logic. But ListViewItem does not implement IComparable. So without a comparer strategy that knows how to do it, ListViewItem is not sortable because it has no default IComparable implementation.

So at the end of the day, it's just another extensibility point that allows you more flexibility when you're not the author of the type that is to be sorted (or you need multiple sorting strategies.)


EDIT: In response to your comment below: "if I have a class that implements IComparer (my own class), this would allow me to sort on any number of properties (a custom sort), why then would I bother using Comparer.Default"

Perhaps an example would help. Let's say you're writing an extension method that checks to see if a given value is between a range.

public static bool Between<T>(this T value, T minValue, T maxValue) {      var comparer = Comparer<T>.Default;      int c1 = comparer.Compare(value, minValue);     int c2 = comparer.Compare(value, maxValue);      return (c1 >= 0 && c2 <= 0);  } 

In this case, I don't know anything about the type T. It may implement IComparable or it may implement IComparable<T> or it may implement neither and an exception will be thrown. This also allows me to easily add an overload for this method that lets the caller pass in their own comparer. But Comparer comes in handy here because it lets me get a default comparer for an unknown type that may or may not implement a generic or non-generic IComparable interface.

like image 37
Josh Avatar answered Sep 23 '22 12:09

Josh