C# › Equality: Equals, GetHashCode & IEquatable

How do you correctly implement IComparable<T> alongside IEquatable<T>, and what consistency rule must they both satisfy together?

Advanced

Answer

IComparable<T>.CompareTo() should return 0 EXACTLY when IEquatable<T>.Equals() returns true, maintaining a consistent notion of equality between the two — a class that says two objects are 'equal' via Equals() but 'not equal' (non-zero CompareTo) via ordering has an internally inconsistent, buggy identity model that can cause sorting and collection bugs.
public class Money : IEquatable<Money>, IComparable<Money> {
  public decimal Amount;
  public bool Equals(Money? other) => other != null && Amount == other.Amount;
  public int CompareTo(Money? other) => Amount.CompareTo(other?.Amount ?? 0);
  // Equals and CompareTo agree: equal amounts -> Equals true AND CompareTo returns 0
}
Real-world example Implementing a value type (like Money or a version number) that needs both correct equality checks and correct sort ordering, consistently.

Common follow-ups: What real bug can occur in a SortedSet<T> or SortedDictionary<TKey,TValue> if CompareTo() and Equals() disagree?