public static class ComparerHelpersComparerComposition
{
public static IComparer<T> Invert<T>(this IComparer<T> comparer) =>
new InvertedComparer<T>(comparer);
public static IComparer<T> ThenBy<T>(this IComparer<T> first, IComparer<T> second) =>
new CompositeComparer<T>(first, second);
public static IComparer<T> ThenByDescending<T>(this IComparer<T> first, IComparer<T> second) =>
new CompositeComparer<T>(first, second.Invert());
public static IComparer<T> Prefer<T>(this IComparer<T> first, Predicate<T> test) =>
first.ThenBy(new TestComparer<T>(test));
public static IComparer<T> Defer<T>(this IComparer<T> first, Predicate<T> test) =>
first.ThenByDescending(new TestComparer<T>(test));
}
public static class ComparerHelpers
{
public static IComparer<T> Invert<T>(this IComparer<T> comparer) =>
new InvertedComparer<T>(comparer);
public static IComparer<T> ThenBy<T>(this IComparer<T> first, IComparer<T> second) =>
new CompositeComparer<T>(first, second);
public static IComparer<T> ThenByDescending<T>(this IComparer<T> first, IComparer<T> second) =>
new CompositeComparer<T>(first, second.Invert());
public static IComparer<T> Prefer<T>(this IComparer<T> first, Predicate<T> test) =>
first.ThenBy(new TestComparer<T>(test));
public static IComparer<T> Defer<T>(this IComparer<T> first, Predicate<T> test) =>
first.ThenByDescending(new TestComparer<T>(test));
}
public static class ComparerComposition
{
public static IComparer<T> Invert<T>(this IComparer<T> comparer) =>
new InvertedComparer<T>(comparer);
public static IComparer<T> ThenBy<T>(this IComparer<T> first, IComparer<T> second) =>
new CompositeComparer<T>(first, second);
public static IComparer<T> ThenByDescending<T>(this IComparer<T> first, IComparer<T> second) =>
new CompositeComparer<T>(first, second.Invert());
public static IComparer<T> Prefer<T>(this IComparer<T> first, Predicate<T> test) =>
first.ThenBy(new TestComparer<T>(test));
public static IComparer<T> Defer<T>(this IComparer<T> first, Predicate<T> test) =>
first.ThenByDescending(new TestComparer<T>(test));
}
class SubReport
{
public static readonly IComparer<SubReport> Comparer =
new NullComparer<SubReport>()CompositeComparer<SubReport>.Empty
.Prefer(sub => sub == null)
.Prefer(sub => sub.Name == "FirstSubReport")
.Prefer(sub => sub.IsIssue)
.Defer(sub => sub.Name == "LastSubReport")
.Defer(sub => sub.Name == "2ndToLast");
public string Name { get; set; }
public bool IsIssue { get; set; }
}
public static class ComparerHelpers
{
public static IComparer<T> Invert<T>(this IComparer<T> comparer) =>
new InvertedComparer<T>(comparer);
public static IComparer<T> ThenBy<T>(this IComparer<T> first, IComparer<T> second) =>
new CompositeComparer<T>(first, second);
public static IComparer<T> ThenByDescending<T>(this IComparer<T> first, IComparer<T> second) =>
new CompositeComparer<T>(first, second.Invert());
public static IComparer<T> Prefer<T>(this IComparer<T> first, Predicate<T> test) =>
first.ThenBy(new TestComparer<T>(test));
public static IComparer<T> Defer<T>(this IComparer<T> first, Predicate<T> test) =>
first.ThenByDescending(new TestComparer<T>(test));
}
Always returns 0.
public class NullComparer<T> : IComparer<T>
{
public int Compare(T x, T y) => 0;
}
Swaps x
and y
, so result is inverted.:
public class CompositeComparer<T> : IComparer<T>
{
public static readonly IComparer<T> Empty = new CompositeComparer<T>();
public CompositeComparer(params IComparer<T>[] comparers)
{
Comparers = comparers;
}
public int Compare(T x, T y) =>
Comparers
.Select(c => c.Compare(x, y))
.FirstOrDefault(r => r != 0);
IComparer<T>[] Comparers { get; }
}
class SubReport
{
public static readonly IComparer<SubReport> Comparer =
new NullComparer<SubReport>()
.Prefer(sub => sub == null)
.Prefer(sub => sub.Name == "FirstSubReport")
.Prefer(sub => sub.IsIssue)
.Defer(sub => sub.Name == "LastSubReport")
.Defer(sub => sub.Name == "2ndToLast");
public string Name { get; set; }
public bool IsIssue { get; set; }
}
public static class ComparerHelpers
{
public static IComparer<T> Invert<T>(this IComparer<T> comparer) =>
new InvertedComparer<T>(comparer);
public static IComparer<T> ThenBy<T>(this IComparer<T> first, IComparer<T> second) =>
new CompositeComparer<T>(first, second);
public static IComparer<T> ThenByDescending<T>(this IComparer<T> first, IComparer<T> second) =>
new CompositeComparer<T>(first, second.Invert());
public static IComparer<T> Prefer<T>(this IComparer<T> first, Predicate<T> test) =>
first.ThenBy(new TestComparer<T>(test));
public static IComparer<T> Defer<T>(this IComparer<T> first, Predicate<T> test) =>
first.ThenByDescending(new TestComparer<T>(test));
}
Always returns 0.
public class NullComparer<T> : IComparer<T>
{
public int Compare(T x, T y) => 0;
}
Swaps x
and y
, so result is inverted.
public class CompositeComparer<T> : IComparer<T>
{
public CompositeComparer(params IComparer<T>[] comparers)
{
Comparers = comparers;
}
public int Compare(T x, T y) =>
Comparers
.Select(c => c.Compare(x, y))
.FirstOrDefault(r => r != 0);
IComparer<T>[] Comparers { get; }
}
class SubReport
{
public static readonly IComparer<SubReport> Comparer =
CompositeComparer<SubReport>.Empty
.Prefer(sub => sub == null)
.Prefer(sub => sub.Name == "FirstSubReport")
.Prefer(sub => sub.IsIssue)
.Defer(sub => sub.Name == "LastSubReport")
.Defer(sub => sub.Name == "2ndToLast");
public string Name { get; set; }
public bool IsIssue { get; set; }
}
public static class ComparerHelpers
{
public static IComparer<T> Invert<T>(this IComparer<T> comparer) =>
new InvertedComparer<T>(comparer);
public static IComparer<T> ThenBy<T>(this IComparer<T> first, IComparer<T> second) =>
new CompositeComparer<T>(first, second);
public static IComparer<T> ThenByDescending<T>(this IComparer<T> first, IComparer<T> second) =>
new CompositeComparer<T>(first, second.Invert());
public static IComparer<T> Prefer<T>(this IComparer<T> first, Predicate<T> test) =>
first.ThenBy(new TestComparer<T>(test));
public static IComparer<T> Defer<T>(this IComparer<T> first, Predicate<T> test) =>
first.ThenByDescending(new TestComparer<T>(test));
}
Swaps x
and y
, so result is inverted:
public class CompositeComparer<T> : IComparer<T>
{
public static readonly IComparer<T> Empty = new CompositeComparer<T>();
public CompositeComparer(params IComparer<T>[] comparers)
{
Comparers = comparers;
}
public int Compare(T x, T y) =>
Comparers
.Select(c => c.Compare(x, y))
.FirstOrDefault(r => r != 0);
IComparer<T>[] Comparers { get; }
}
Well, I do not actually think that the following is the shortest solution, but it is SOLID, so is maintainable, extendable, and reusable. First of all – how to use:
class SubReport
{
public static readonly IComparer<SubReport> Comparer =
new NullComparer<SubReport>()
.Prefer(sub => sub == null)
.Prefer(sub => sub.Name == "FirstSubReport")
.Prefer(sub => sub.IsIssue)
.Defer(sub => sub.Name == "LastSubReport")
.Defer(sub => sub.Name == "2ndToLast");
public string Name { get; set; }
public bool IsIssue { get; set; }
}
What we consume here are the following (classes are short, so there is probably no need to explain the code – I basically combine multiple implementations of IComparer<T>
):
public static class ComparerHelpers
{
public static IComparer<T> Invert<T>(this IComparer<T> comparer) =>
new InvertedComparer<T>(comparer);
public static IComparer<T> ThenBy<T>(this IComparer<T> first, IComparer<T> second) =>
new CompositeComparer<T>(first, second);
public static IComparer<T> ThenByDescending<T>(this IComparer<T> first, IComparer<T> second) =>
new CompositeComparer<T>(first, second.Invert());
public static IComparer<T> Prefer<T>(this IComparer<T> first, Predicate<T> test) =>
first.ThenBy(new TestComparer<T>(test));
public static IComparer<T> Defer<T>(this IComparer<T> first, Predicate<T> test) =>
first.ThenByDescending(new TestComparer<T>(test));
}
Always returns 0.
public class NullComparer<T> : IComparer<T>
{
public int Compare(T x, T y) => 0;
}
Swaps x
and y
, so result is inverted.
public class InvertedComparer<T> : IComparer<T>
{
public InvertedComparer(IComparer<T> inner)
{
Inner = inner;
}
public int Compare(T x, T y) =>
Inner.Compare(y, x);
IComparer<T> Inner { get; }
}
Implements multilevel sorting:
public class CompositeComparer<T> : IComparer<T>
{
public CompositeComparer(params IComparer<T>[] comparers)
{
Comparers = comparers;
}
public int Compare(T x, T y) =>
Comparers
.Select(c => c.Compare(x, y))
.FirstOrDefault(r => r != 0);
IComparer<T>[] Comparers { get; }
}
To sort by condition match:
public class TestComparer<T> : IComparer<T>
{
public TestComparer(Predicate<T> test)
{
Test = test;
}
public int Compare(T x, T y)
{
var testX = Test(x);
var testY = Test(y);
return testX
? (testY ? 0 : -1)
: (testY ? 1 : 0);
}
Predicate<T> Test { get; }
}
Please note that you can use this extension methods to compose comparers for other purposes, like multilevel multidirectional sorting. Hope it helps.