Created
June 17, 2015 15:17
-
-
Save RichardD2/7e14217426d999db3d21 to your computer and use it in GitHub Desktop.
Extension methods for working with IComparer<T> classes.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
namespace NBS.Core.Collections.Generic | |
{ | |
public static class ComparerExtensions | |
{ | |
private sealed class ReverseComparer<T> : IComparer<T> | |
{ | |
public readonly IComparer<T> Original; | |
public ReverseComparer(IComparer<T> original) | |
{ | |
Original = original; | |
} | |
public int Compare(T x, T y) | |
{ | |
// NB: Reverse the order of the comparands; | |
// DO NOT negate the result of the comparison. | |
// If the original comparer returns int.MinValue, | |
// negating the result will have no effect. | |
// (-int.MinValue === int.MinValue) | |
return Original.Compare(y, x); | |
} | |
} | |
public static IComparer<T> Reverse<T>(this IComparer<T> comparer) | |
{ | |
if (comparer == null) throw new ArgumentNullException("comparer"); | |
var reversed = comparer as ReverseComparer<T>; | |
if (reversed != null) return reversed.Original; | |
return new ReverseComparer<T>(comparer); | |
} | |
private sealed class ComparisonComparer<T> : IComparer<T> | |
{ | |
private readonly Comparison<T> _comparison; | |
private readonly bool _descending; | |
public ComparisonComparer(Comparison<T> comparison, bool descending) | |
{ | |
_comparison = comparison; | |
_descending = descending; | |
} | |
public int Compare(T x, T y) | |
{ | |
// NB: Reverse the order of the comparands; | |
// DO NOT negate the result of the comparison. | |
// If the original comparer returns int.MinValue, | |
// negating the result will have no effect. | |
// (-int.MinValue === int.MinValue) | |
return _descending ? _comparison(y, x) : _comparison(x, y); | |
} | |
} | |
public static IComparer<T> ToComparer<T>(this Comparison<T> comparison, bool descending = false) | |
{ | |
if (comparison == null) throw new ArgumentNullException("comparison"); | |
return new ComparisonComparer<T>(comparison, descending); | |
} | |
private sealed class ExpressionComparer<TValue, TKey> : IComparer<TValue> | |
{ | |
private readonly IComparer<TKey> _keyComparer; | |
private readonly Func<TValue, TKey> _expression; | |
private readonly bool _descending; | |
public ExpressionComparer(Func<TValue, TKey> expression, bool descending, IComparer<TKey> keyComparer) | |
{ | |
if (keyComparer == null) keyComparer = Comparer<TKey>.Default; | |
_expression = expression; | |
_keyComparer = keyComparer; | |
_descending = descending; | |
} | |
public int Compare(TValue x, TValue y) | |
{ | |
// NB: Reverse the order of the comparands; | |
// DO NOT negate the result of the comparison. | |
// If the original comparer returns int.MinValue, | |
// negating the result will have no effect. | |
// (-int.MinValue === int.MinValue) | |
return _descending ? CompareCore(y, x) : CompareCore(x, y); | |
} | |
private int CompareCore(TValue x, TValue y) | |
{ | |
if (x == null) return y == null ? 0 : -1; | |
if (y == null) return 1; | |
return _keyComparer.Compare(_expression(x), _expression(y)); | |
} | |
} | |
public static IComparer<TValue> ToComparer<TValue, TKey>(this Func<TValue, TKey> expression, bool descending = false, IComparer<TKey> keyComparer = null) | |
{ | |
if (expression == null) throw new ArgumentNullException("expression"); | |
return new ExpressionComparer<TValue, TKey>(expression, descending, keyComparer); | |
} | |
private sealed class CompoundComparer<T> : IComparer<T> | |
{ | |
private readonly IComparer<T> _first; | |
private readonly IComparer<T> _second; | |
public CompoundComparer(IComparer<T> first, IComparer<T> second) | |
{ | |
_first = first; | |
_second = second; | |
} | |
public int Compare(T x, T y) | |
{ | |
int result = _first.Compare(x, y); | |
if (result == 0) result = _second.Compare(x, y); | |
return result; | |
} | |
} | |
public static IComparer<T> ThenBy<T>(this IComparer<T> first, IComparer<T> second) | |
{ | |
if (first == null) throw new ArgumentNullException("first"); | |
if (second == null) throw new ArgumentNullException("second"); | |
return new CompoundComparer<T>(first, second); | |
} | |
public static IComparer<T> ThenByDescending<T>(this IComparer<T> first, IComparer<T> second) | |
{ | |
if (first == null) throw new ArgumentNullException("first"); | |
if (second == null) throw new ArgumentNullException("second"); | |
return first.ThenBy(second.Reverse()); | |
} | |
public static IComparer<T> ThenBy<T>(this IComparer<T> first, Comparison<T> comparison) | |
{ | |
if (first == null) throw new ArgumentNullException("first"); | |
if (comparison == null) throw new ArgumentNullException("comparison"); | |
return first.ThenBy(comparison.ToComparer(false)); | |
} | |
public static IComparer<T> ThenByDescending<T>(this IComparer<T> first, Comparison<T> comparison) | |
{ | |
if (first == null) throw new ArgumentNullException("first"); | |
if (comparison == null) throw new ArgumentNullException("comparison"); | |
return first.ThenBy(comparison.ToComparer(true)); | |
} | |
public static IComparer<T> ThenBy<T, TKey>(this IComparer<T> first, Func<T, TKey> expression, IComparer<TKey> keyComparer = null) | |
{ | |
if (first == null) throw new ArgumentNullException("first"); | |
if (expression == null) throw new ArgumentNullException("expression"); | |
return first.ThenBy(expression.ToComparer(false, keyComparer)); | |
} | |
public static IComparer<T> ThenByDescending<T, TKey>(this IComparer<T> first, Func<T, TKey> expression, IComparer<TKey> keyComparer = null) | |
{ | |
if (first == null) throw new ArgumentNullException("first"); | |
if (expression == null) throw new ArgumentNullException("expression"); | |
return first.ThenBy(expression.ToComparer(true, keyComparer)); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment