Click here to Skip to main content
15,904,494 members
Articles / Programming Languages / C#
Tip/Trick

ChainedComparer as Fluent Implementation for IComparer<T>

Rate me:
Please Sign up or sign in to vote.
4.75/5 (3 votes)
18 Jun 2015CPOL 5.6K   5  
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:

C#
...
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:

C#
// 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, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Founder eXternSoft GmbH
Switzerland Switzerland
I feel comfortable on a variety of systems (UNIX, Windows, cross-compiled embedded systems, etc.) in a variety of languages, environments, and tools.
I have a particular affinity to computer language analysis, testing, as well as quality management.

More information about what I do for a living can be found at my LinkedIn Profile and on my company's web page (German only).

Comments and Discussions

 
-- There are no messages in this forum --