C #, возможно, мог просто запутать представление в System.Object о том, как вы упорядочиваете объекты, как это было сделано с Equals
, чтобы сравнить их на предмет идентичности.
К сожалению, это приводит к проблемам интенсиональности и экстенсиональности, локализации и т. Д.
Существует интерфейс IComparable<T>
, но встроенные типы значений не могут реализовывать подобные интерфейсы.
Следовательно, нет хорошего способа просто посмотреть на тип во время компиляции и точно знать, имеет ли он осмысленный порядок. = (
Механизм, который развился в C #, состоит в том, чтобы использовать экземпляр IComparer<T>
, возвращаемый Comparer<T>.Default
, и получать ошибку во время выполнения при попытке отсортировать что-либо, в котором отсутствует упорядоченность.
Допуская несколько IComparer
с и IComparer<T>
с, вы можете иметь представление о нескольких альтернативных упорядочениях, которые работают с одним и тем же типом, так что многое хорошо, но не все хорошо.
Внутренне, c # использует набор правил для поиска Comparer<T>.Default
, который обрабатывается по-разному, если T является экземпляром IComparable<T>
или имеет форму Nullable<T>
и т. Д.
например. код из system / collection / generic / comparer.cs :
public static Comparer<T> Default {
get {
Comparer<T> comparer = defaultComparer;
if (comparer == null) {
comparer = CreateComparer();
defaultComparer = comparer;
}
return comparer;
}
}
private static Comparer<T> CreateComparer() {
Type t = typeof(T);
// If T implements IComparable<T> return a GenericComparer<T>
if (typeof(IComparable<T>).IsAssignableFrom(t)) {
//return (Comparer<T>)Activator.CreateInstance(typeof(GenericComparer<>).MakeGenericType(t));
return (Comparer<T>)(typeof(GenericComparer<int>).TypeHandle.CreateInstanceForAnotherGenericParameter(t));
}
// If T is a Nullable<U> where U implements IComparable<U> return a NullableComparer<U>
if (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Nullable<>)) {
Type u = t.GetGenericArguments()[0];
if (typeof(IComparable<>).MakeGenericType(u).IsAssignableFrom(u)) {
//return (Comparer<T>)Activator.CreateInstance(typeof(NullableComparer<>).MakeGenericType(u));
return (Comparer<T>)(typeof(NullableComparer<int>).TypeHandle.CreateInstanceForAnotherGenericParameter(u));
}
}
// Otherwise return an ObjectComparer<T>
return new ObjectComparer<T>();
}
По сути, это позволяет Microsoft постепенно добавлять специальные случаи для своего собственного кода, но, к сожалению, код, который получается в результате использования Comparer<T>.Default
для пользовательского IComparable<T>
экземпляра, довольно ужасен.
Метод Sort в IList<T>
предполагает, что Comparer<T>.Default
найдет что-то, что он может использовать для сравнения ваших объектов, но у него нет способа посмотреть на тип T и сказать, что он есть, поэтому он предполагает является безопасным и осознает только позже во время выполнения, что MyClass
не подыгрывает.