Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

ChainedComparer as Fluent Implementation for IComparer<T>

0.00/5 (No votes)
18 Jun 2015 1  
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

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here