Re: Компаратор
От: _FRED_ Черногория
Дата: 27.06.11 21:22
Оценка: 8 (2) +1
Здравствуйте, G-Host, Вы писали:

GH>Довольно часто приходится передавать IComparer<> в разные методы.

GH>Для пользовательских классов приходится создавать класс, наследовать и т.п., да еще и хранить ссылку на экземпляр отдельно
GH>чтобы то и дело не было создания.
GH>Когда намного проще было бы написать лямбду "на месте".

Был такой замечательный советский фильм про конструкторов ракет (начинавших ещё в довоенные годы). Так там вот один такой "молодой" конструктор приходит к двум уже "заматеревшим" и показывает свои чертежи. А те смотрят и спрашивают: "Шестой вариант уже поди?" — "а откуда вы знаете" — "А вот когда тридцатый (тут точную цифру забыл я) сделаешь, сам поймёшь"

Далее сначала добавляется ещё один (Convert) "самый полезный метод":

  public static partial class Comparers
  {
    public static Comparer<T> Create<T>(Comparison<T> comparison) {
      Argument.NotNull(comparison, "comparison");
      return new ComparisonComparer<T>(comparison);
    }

    public static Comparer<TOutput> Convert<TInput, TOutput>(this IComparer<TInput> comparer, Converter<TOutput, TInput> converter) {
      Argument.NotNull(comparer, "comparer");
      Argument.NotNull(converter, "converter");

      Comparison<TOutput> comparison = (x, y) => comparer.Compare(converter(x), converter(y));
      return Create(comparison);
    }

    [Serializable]
    private sealed class ComparisonComparer<T> : Comparer<T>
    {
      public ComparisonComparer(Comparison<T> comparison) {
        Argument.NotNull(comparison, "comparison");
        Comparison = comparison;
      }

      private Comparison<T> Comparison { get; set; }

      [ContractInvariantMethod]
      private void Invariant() {
        Contract.Invariant(Comparison != null);
      }

      public override int Compare(T x, T y) {
        return Comparison(x, y);
      }
    }
  }
  Потом другой:
  public static partial class Comparers
  {
    public static Comparer<T> Reverse<T>(this IComparer<T> comparer) {
      Argument.NotNull(comparer, "comparer");
      return new ReverseComparer<T>(comparer);
    }

    public static Comparer<T> DefaultReverse<T>() {
      return ReverseComparer<T>.Default;
    }

    [Serializable]
    private sealed class ReverseComparer<T> : Comparer<T>
    {
      private static readonly ReverseComparer<T> @default = new ReverseComparer<T>(Comparer<T>.Default);

      public ReverseComparer(IComparer<T> comparer) {
        Argument.NotNull(comparer, "comparer");
        Original = comparer;
      }

      public static new ReverseComparer<T> Default {
        [DebuggerStepThrough]
        get { return @default; }
      }

      private IComparer<T> Original { get; set; }

      [ContractInvariantMethod]
      private void Invariant() {
        Contract.Invariant(Original != null);
      }

      public override int Compare(T x, T y) {
        return Original.Compare(y, x);
      }
    }
  }
  Третий…
  public static partial class Comparers
  {
    public static Comparer<T> ThenBy<T>(this IComparer<T> first, IComparer<T> second) {
      Argument.NotNull(first, "first");
      Argument.NotNull(second, "second");

      return new ThenByComparer<T>(first, second);
    }

    [Serializable]
    private sealed class ThenByComparer<T> : Comparer<T>
    {
      public ThenByComparer(IComparer<T> first, IComparer<T> second) {
        Argument.NotNull(first, "first");
        Argument.NotNull(second, "second");

        First = first;
        Second = second;
      }

      private IComparer<T> First { get; set; }
      private IComparer<T> Second { get; set; }

      [ContractInvariantMethod]
      private void Invariant() {
        Contract.Invariant(First != null);
        Contract.Invariant(Second != null);
      }

      public override int Compare(T x, T y) {
        var value = First.Compare(x, y);
        if(value == 0) {
          return Second.Compare(x, y);
        }//if
        return value;
      }
    }
  }
  Ну и до кучи
  public static partial class Comparers
  {
    public static bool Equals<T>(this IComparer<T> comparer, T left, T right) {
      Argument.NotNull(comparer, "comparer");
      return comparer.Compare(left, right) == 0;
    }

    public static bool NotEquals<T>(this IComparer<T> comparer, T left, T right) {
      Argument.NotNull(comparer, "comparer");
      return comparer.Compare(left, right) != 0;
    }

    public static bool LessThan<T>(this IComparer<T> comparer, T left, T right) {
      Argument.NotNull(comparer, "comparer");
      return comparer.Compare(left, right) < 0;
    }

    public static bool LessThanOrEqual<T>(this IComparer<T> comparer, T left, T right) {
      Argument.NotNull(comparer, "comparer");
      return comparer.Compare(left, right) <= 0;
    }

    public static bool GreaterThan<T>(this IComparer<T> comparer, T left, T right) {
      Argument.NotNull(comparer, "comparer");
      return comparer.Compare(left, right) > 0;
    }

    public static bool GreaterThanOrEqual<T>(this IComparer<T> comparer, T left, T right) {
      Argument.NotNull(comparer, "comparer");
      return comparer.Compare(left, right) >= 0;
    }
  }

А остальное уж совсем экзотика

Тут полезно что: наружу выдаётся не IComparer<>, а Comaprer<>, качественное отличие которого в том, что он так же реализует и не-дженерик IComparer и его можно использовать в больше количестве сценариев и даётся это совершенно забесплатно.

Метод Convert позволяет отсортировать, например, коллекцию бизнес-объектов по какому-либо полю, а ThenBy по совокупности полей.
Help will always be given at Hogwarts to those who ask for it.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.