Both the interfaces seem to compare objects for equality, so what are the major differences between them?
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.
IEquatable<T>
for equality.
IComparable<T>
for ordering.
In addition to Greg D's answer:
You might implement IComparable
without implementing IEquatable
for a class where a partial ordering makes sense, and where you very definitely want the consumer to infer that just because CompareTo()
returns zero, this does not imply that the objects are equal (for anything other than sorting purposes).
IComparable
is wholly inappropriate here. What you’ve got is a very particular ordering that only applies in one special situation. For such situations, implementing a general IComparable
is wrong. This is what IComparer
s are there for. For example, people cannot be ordered meaningfully. But they can be ordered according to their salary, their shoe size, the number of their freckles or their weight. Hence, we would implement different IComparer
s for all these cases. –
Westbrooke IComparer
interface. –
Westbrooke IComparer
implementations rather than being imposed as the default one. In fact, I believe that as soon as an object becomes a bit complex, it's generally good reason enough not to have it implement IComparable
at all and systematically use a separate comparer. –
Cloyd CompareTo(...) == 0
should imply equality. Earlier you asked for an example where that might not be the case. How about names that are case-preserving, but case-insensitive for equality? In other words, I can have a name "a" and "A", (case is preserved), and they're considered equal (perhaps by converting both to uppercase, just for the equality check). However, for sorting purposes, we want to treat them case sensitively, so they're sorted logically according to cultural rules. Would that justify equality and comparison yielding different results? –
Hiramhirasuna IComparable
was required to imply equality for a return value of zero. Clearly it's now 13 years later since you made that observation, but it's worth noting that today the MS docs on IComparable and IComparable<T> no longer make such an assertion. I don't know if this indicates a softening in MS's thinking on this. –
Hiramhirasuna angstrom
, ångström
, etc. to compare equal, but when sorting them you would generally sort unadorned Latin letters before their modified variants. I still think this merits using a specific comparer rather than putting these semantics into the IComparable
implementation: the latter just seems error-prone. It's interesting that the MSDN wording has been softened in that regard. –
Westbrooke As stated on the MSDN Page for IEquatable:
The IComparable interface defines the
CompareTo
method, which determines the sort order of instances of the implementing type. The IEquatable interface defines theEquals
method, which determines the equality of instances of the implementing type.
Equals
vs. CompareTo
IComparable <T>
defines a type specific comparison method which can be used to order or sort objects.
IEquatable <T>
defines a generalized method which can be used to implement for determining equality.
Let's say you have Person class
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
Person p1 = new Person() { Name = "Person 1", Age = 34 };
Person p2 = new Person() { Name = "Person 2", Age = 31 };
Person p3 = new Person() { Name = "Person 3", Age = 33 };
Person p4 = new Person() { Name = "Person 4", Age = 26 };
List<Person> people = new List<Person> { p1, p2, p3, p4 };
To sort these objects you can use people.Sort();
.
But this will thrown an an exception.
Framework doesn't know how to sort these objects. You need to tell how to sort implementing IComparable
interface.
public class Person : IComparable
{
public string Name { get; set; }
public int Age { get; set; }
public int CompareTo(object obj)
{
Person otherPerson = obj as Person;
if (otherPerson == null)
{
throw new ArgumentNullException();
}
else
{
return Age.CompareTo(otherPerson.Age);
}
}
}
This will sort the array properly with Sort()
method.
Next to compare two objects you can use Equals()
method.
var newPerson = new Person() { Name = "Person 1", Age = 34 };
var newPersonIsPerson1 = newPerson.Equals(p1);
This will return false
because Equals
method doesn't know how to compare two objects. Therefore you need to implement IEquatable
interface and tell the framework how to do the comparison. Extending on the previous example it'll look like this.
public class Person : IComparable, IEquatable<Person>
{
//Some code hidden
public bool Equals(Person other)
{
if (Age == other.Age && Name == other.Name)
{
return true;
}
else
{
return false;
}
}
}
IEquatable
use a generic <Person>
and IComparable
does not? –
Menology © 2022 - 2024 — McMap. All rights reserved.
IComparable
properly. Can you come up with a meaningful example whereCompareTo(…) == 0
does not imply equality? I certainly can’t. In fact, the interface contract (as per MSDN) requires thatCompareTo(…) == 0
implies equality. To put it bluntly, in such a case as yours, use a specialComparator
object, do not implementIComparable
. – Westbrooke