ChainedComparer as Fluent Implementation for IComparer<T>






4.75/5 (3 votes)
A generic fluent implementation for a prioritized IComparer class
Introduction
Inspired by the Q&A item Func<TElement, TKey1, TKey2> To IComparer<TElement>?", I came up with a generic fluent interface for a prioritized IComparer<T>. This tip publishes my solution for that Q&A above (well, it's basically a copy of it ;-)).
Using the Code
The ChainedComparer
implements the fluent interface. A fluent interface is implemented here as a "cascate of methods".
Example usage:
...
IComparer<MyRecordType> compareByYearAndMonth = ChainedComparer<MyRecordType>
.First(d => d.Year)
.Then (d => d.Month);
myContainer.Sort(compareByYearAndMonth);
...
Note: You can chain any number of .Then(...)
.
Implementation
The ChainedComparer
implementation is shown below:
// Comparer for a prioritized sequence of comparison attributes.
// Implemented as "fluent interface", i.e. usage:
// ChainedComparer<MyType>.First(v=>v.Prop1).Then(v=>v.Prop2)...Then(v=>v.PropN);
public class ChainedComparer<TValue> : IComparer<TValue>
{
// sequence of comparison stages: 1st has 1st priority, next has next priority, etc.
private List<Func<TValue, TValue, int>> _stages;
// private construction. For named constructor see First(...)
private ChainedComparer() { _stages = new List<Func<TValue,TValue,int>>(); }
// named constructor - takes selector for first property for comparison
public static ChainedComparer<TValue> First<TDimension>(Func<TValue, TDimension> selector)
where TDimension : IComparable<TDimension>
{
return new ChainedComparer<TValue>().Then(selector);
}
// selector for next comparison stage
public ChainedComparer<TValue> Then<TDimension>(Func<TValue, TDimension> selector)
where TDimension : IComparable<TDimension>
{
_stages.Add((a, b) => selector(a).CompareTo(selector(b)));
return this;
}
// implementation of IComparer<T> interface
public int Compare(TValue a, TValue b)
{
return _stages.Select(compare => compare(a, b)).FirstOrDefault(res => res != 0);
}
}
History
- 2015-06-18: Initial version