Обобщённый компаратор для Array.Sort()

Рейтинг: 2Ответов: 2Опубликовано: 14.04.2015

Есть компаратор для сортирования в обратном порядке.

class Comp<T> : IComparer<T> where T : IComparable<T>
{

    public int Compare(T x, T y)
    {
        return -x.CompareTo(y);
        //return  y - x;
    }
}

Вопрос: можно ли сделать так, чтоб можно было возвращать y - x в качестве результата сравнения, как в закомментированном участке(это мешает сделать обобщённый тип Т)

Ответы

▲ 4Принят

Нет. Операторы не могут использоваться с generic-типами, поскольку они статические и на них нельзя наложить ограничение даже при помощи интерфейса.

Что касается вычитания для сравнения, да и унарного минуса - могут быть проблемы из-за переполнения. Хотя, стандартный Enumerable.OrderByDescending уже содержит этот баг: http://codeblog.jonskeet.uk/2015/03/02/backward-compatibility-pain/

PS: На самом деле, способ с вычитанием можно упихать, заставив определять типы и искать оператор во время исполнения метода, но это будет очень большим ударом по производительности, особенно с учётом того, что компараторы обычно используются при сортировке.

А самый хороший способ сделать обратный компаратор - это

public int Compare(T x, T y)
{
  return y.CompareTo(x);
}
▲ 2

Такой возможности не существует потому, что на текущий момент невозможно выразить в C# ограничение для generic-типа, гарантирующее существование того или иного оператора. (Однако, поддержка этого обсуждается командой разработчиков языка.)

Однако, ваш код с вычитанием неправилен даже если T = int. Представьте себе, что x == int.MaxValue, y == -1, тогда x - y станет отрицательным из-за переполнения.

Правильно по идее так:

return -Math.Sign(x.CompareTo(y));