Основное различие между IComparable и IComparable <> заключается в том, что первый из них является pre-generics, поэтому позволяет вызывать метод сравнения с любым объектом, тогда как второй требует, чтобы он имел общий тип:
IComparable - CompareTo(object other);
IComparable<T> - CompareTo(T other);
Я бы выбрал второй вариант при условии, что вы не собираетесь использовать какие-либо старые библиотеки .net 1.0, где типы могут не реализовывать современное универсальное решение. Вы получите повышение производительности, так как будете избегать бокса, и при сравнении не нужно будет проверять соответствие типов, а также вы почувствуете теплое чувство, возникающее при выполнении самых передовых задач ...
В связи с очень хорошим и уместным замечанием Джеффа я бы сказал, что хорошей практикой является наложение на общее число стольких ограничений, сколько требуется для выполнения задачи. Поскольку вы полностью контролируете код внутри обобщенного кода, вы знаете, используете ли вы какие-либо методы, требующие базового типа IComparable. Итак, принимая во внимание его комментарий, я лично буду придерживаться следующих правил:
Если вы не ожидаете, что универсальный объект будет использовать какие-либо типы, которые только реализуют IComparable (то есть устаревший код 1.0), и вы не вызываете какие-либо методы из универсального, которые полагаются на параметр IComparable затем используйте только ограничение IComparable <>.
Если вы используете типы, которые реализуют только IComparable, используйте только это ограничение
Если вы используете методы, для которых требуется параметр IComparable, но не используете типы, которые реализуют только IComparable, то использование обоих ограничений, как в ответе Джеффа, повысит производительность при использовании методов, которые принимают универсальный тип.
Чтобы расширить третье правило, давайте предположим, что класс, который вы пишете, выглядит следующим образом:
public class StrangeExample<T> where ... //to be decided
{
public void SortArray(T[] input)
{
Array.Sort(input);
}
public bool AreEqual(T a, T b)
{
return a.CompareTo(b) == 0;
}
}
И нам нужно решить, какие ограничения на него наложить. Метод SortArray вызывает Array.Sort, для которого требуется, чтобы передаваемый массив содержал объекты, реализующие IComparable. Поэтому мы должны иметь ограничение IComparable:
public class StrangeExample<T> where T : IComparable
Теперь класс будет скомпилирован и работать правильно, так как массив T допустим для Array.Sort, и в интерфейсе определен допустимый метод .CompareTo. Однако, если вы уверены, что не захотите использовать свой класс с типом, который также не реализует интерфейс IComparable <>, вы можете расширить свое ограничение до:
public class StrangeExample<T> where T : IComparable, IComparable<T>
Это означает, что при вызове AreEqual будет использоваться более быстрый общий метод CompareTo, и вы увидите выигрыш в производительности за счет невозможности использовать его со старыми типами .NET 1.0.
С другой стороны, если у вас не было метода AreEqual, тогда ограничение IComparable <> не дает никаких преимуществ, поэтому вы можете его также отбросить - вы все равно используете реализации IComparable.