Skip to main content
Code Review

Return to Answer

added 4 characters in body
Source Link
Dmitry Nogin
  • 6.1k
  • 3
  • 21
  • 40
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));
}
deleted 43 characters in body
Source Link
Dmitry Nogin
  • 6.1k
  • 3
  • 21
  • 40
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; }
}
Source Link
Dmitry Nogin
  • 6.1k
  • 3
  • 21
  • 40

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.

lang-cs

AltStyle によって変換されたページ (->オリジナル) /