When to use IComparableT Vs. IComparerT
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.
Difference between .Equals, IComparable and IComparer
Well first off, on the surface, Equals
is a method (present in every object), while IComparable
and IComparer
are interfaces.
Equals
is present in any class and can be overriden to provide equality testing depending on the context of the class (it's a good practice to override GetHashCode
as well). By default it just tests if objects are equal in memory which is not very useful. Equals
(and GetHashCode
) are usually given a different implementation in the context of searching or hashing.
Implementing IComparable
is a more fine-grain way of comparison, as it provides the CompareTo
method, which is a greater-than/less-than comparison as opposed to Equals
which is simply a is-equal-or-not comparison. For example a binary search tree structure could benefit from this method.
IComparer
is similar to IComparable
, except that it works from the outside. It allows you to define a "neutral" object that is used for comparing two other objects without modifying them directly, which you need to do with IComparable
.
What's the difference between IComparable & IEquatable interfaces?
IEquatable
tests whether two objects are equal.
IComparable
imposes a total ordering on the objects being compared.
For example, IEquatable
would tell you that 5 is not equal to 7. IComparable
would tell you that 5 comes before 7.
C# IComparable IComparer with additional Param
You cannot pass extra arguments to IComparer
's Compare
method, because method signature must match the signature in the interface.
What you can do is to construct an instance of IComparer
with the extra parameter, store it in the instance, and use inside CompareTo
as needed:
class MyComparer : IComparer<object> {
private readonly IDictionary<int, int> preferences;
public MyComparer(IDictionary<int, int> preferences) {
this.preferences = preferences;
}
public int Compare(object a, object b) {
... // Perform the comparison with preferences in scope
}
}
How to sort a list of objects with IComparable and IComparer
First, there's no need to have an IComparer<Employee>
that sorts by descending if your Employee
class implements IComparable<Employee>
using the same sort criteria. And it's horribly inefficient for your Employee
class to instantiate a new IComparer<Employee>
for every comparision.
You should change your Employee
class so that its CompareTo
looks like this:
int CompareTo(Employee next)
{
return next.NumberOfKids.CompareTo(this.NumberOfKids);
}
Then you can ditch the EmployeeComparer
altogether and sort like this:
list = list.Take(3).ToList();
list.Sort(); // Uses default IComparable for the Employee class
return list;
Typically, you make the IComparable<T>
implementation on the class perform the default sorting order. In the case of employees, that'd probably either be by employee ID or perhaps last name, first name. IComparer<T>
implementations should be for other sorting criteria.
With List<T>
, though, you have another option: use an anonymous function. For example, you could do this by writing:
list.Sort((x, y) => y.NumberOfKids.CompareTo(x.NumberOfKids));
See this List.Sort overload.
Or, you could just ditch the whole idea of IComparer<T>
and IComparable<T>
and List.Sort
altogether and do it the LINQ way:
var result = list.Take(3).OrderByDescending(x => x.NumberOfKids).ToList();
Sorting an ArrayList by using IComparer Compare Function C#
You'd better use the IComparable<>
interface.
"The object to be sorted will implement IComparable while the class that is going to sort the objects will implement IComparer."
Source: difference between IComparable and IComparer
public class Point : IComparable<Point>
{
public int x;
public int y;
public Point(int x_Point, int y_Point)
{
x = x_Point;
y = y_Point;
}
public int CompareTo(Point other)
{
if (this.x == other.x && this.y == other.y)
return 0;
if (this.y < other.y)
return -1;
if (this.y == other.y && this.x < other.x)
return -1;
return 1;
}
}
public static void Main()
{
var AL = new List<Point>(); // ditch the ArrayList for good... ;-)
Random R = new Random();
for (int i = 0; i < 10; i++)
{
Point p = new Point(R.Next(50), R.Next(50));
AL.Add(p);
}
PrintValues(AL);
AL.Sort();
PrintValues(AL);
}
C# Generic Collections, IComparer, IComparable and IEquatable
IComparable<T>
is the preferred mechanism to provide comparison support for sorting. The advice of implementing the comparison operators doesn't make a lot of sense for most types, and they could not be utilized by generic collections anyway. You should also implement IEquatable<T>
, override GetHashCode()
, and override object.Equals
to delegate to IEquatable<T>.Equals
.
In general, whenever I implement IComparable<T>
, I also implement the non-generic IComparable
, but I implement IComparable.CompareTo
explicitly such that it is normally hidden.
Related Topics
Execute Multiple Queries in Single Oracle Command in C#
How to Bind to a Dynamicresource So You Can Use a Converter or Stringformat, etc.? (Revision 4)
Auto-Resize Multiple Forms Rendered on Panel
The Bare Minimum Needed to Write a Msmq Sample Application
How to Write a Unit Test to Determine Whether an Object Can Be Garbage Collected
Converting an Int[] to Byte[] in C#
Pass Multiple Complex Objects to a Post/Put Web API Method
How to Prevent an Exception in a Background Thread from Terminating an Application
Setting Culture for ASP.NET MVC Application on VS Dev Server and Iis
Do I Have to Close() a SQLconnection Before It Gets Disposed
Using C# to Authenticate User Against Ldap
Removing the Delay After Keydown Event
Why Does the Is Operator Return False When Given Null
Total Number of Items Defined in an Enum
Open a Folder Using Process.Start