Defining Default Comparers for a Type - StephenCleary/Comparers GitHub Wiki
A type may easily define its default comparer by deriving from ComparableBase:
public sealed class Person : ComparableBase<Person>
{
static Person()
{
DefaultComparer = Compare<Person>.OrderBy(p => p.LastName).ThenBy(p => p.FirstName);
}
public string FirstName { get; set; }
public string LastName { get; set; }
}
Person.DefaultComparer is defined by ComparableBase<Person>, and is used by both Compare<T>.Default() and Comparer<T>.Default.
Note: DefaultComparer should only be set once, in the static constructor!
If a class can only implement IEquatable<T>, then it can derive from EquatableBase<T>, which is identical to ComparableBase<T> except DefaultComparer is an IFullEqualityComparer<T>.
If Person has another base class it wants to derive from, it can still define a default comparer by implementing the relevant interfaces directly and using the ComparableImplementations class:
public sealed class Person : MyBase, IEquatable<Person>, IComparable<Person>, IComparable
{
static public readonly IComparer<Person> DefaultComparer = Compare<Person>.OrderBy(p => p.LastName).ThenBy(p => p.FirstName);
public string FirstName { get; set; }
public string LastName { get; set; }
public override int GetHashCode()
{
return ComparableImplementations.ImplementGetHashCode(DefaultComparer, this);
}
public override bool Equals(object obj)
{
return ComparableImplementations.ImplementEquals(DefaultComparer, this, obj);
}
public bool Equals(Person other)
{
return ComparableImplementations.ImplementEquals(DefaultComparer, this, other);
}
int IComparable.CompareTo(object obj)
{
return ComparableImplementations.ImplementCompareTo(DefaultComparer, this, obj);
}
public int CompareTo(Person other)
{
return ComparableImplementations.ImplementCompareTo(DefaultComparer, this, other);
}
}
The XML documentation for the ComparableImplementations methods will remind you to provide all the correct overloads and implementations.
Operator overloads (==, !=, <, <=, >, and >=) are provided for any type deriving from ComparableBaseWithOperators:
public sealed class Person : ComparableBaseWithOperators<Person>
{
static Person()
{
DefaultComparer = Compare<Person>.OrderBy(p => p.LastName).ThenBy(p => p.FirstName);
}
public Person(string firstName, string lastName)
{
FirstName = firstName;
LastName = lastName;
}
public string FirstName { get; private set; }
public string LastName { get; private set; }
}
Note that operator overloading is only recommended for immutable types.
There is also an EquatableBaseWithOperators<T> for equatable types.