Страницы

Поиск по вопросам

среда, 19 декабря 2018 г.

Для чего нужен интерфейс icomparable? - простыми словами

Для чего нужен интерфейс icomparable? Я новичок и прошу объяснить на пальцах зачем он нужен и что он делает?


Ответ

tl;dr: Интерфейс IComparable нужен потому, что иначе нельзя использовать сравнение в функциях, которые работают с произвольным типом данных.

Смотрите.
Для того, чтобы упорядочить объекты, их нужно сравнивать. Если тип объектов известен заранее, то для сравнения проще всего использовать операторы >/=
Теперь вопрос, а как же сравнивать объекты, если тип их неизвестен? Например, если у нас есть набор элементов произвольного типа (например, generic-типа T)? Для того, чтобы выразить идею «объект X что-то умеет», в .NET используются интерфейсы
Но в интерфейсе нельзя выразить «объект умеет сравниваться с другим». Поэтому и был придуман интерфейс IComparable (а также его более современный собрат IComparable), который описывает операцию сравнения.
Пример: пускай вы хотите написать функцию Max, которая находит максимальный элемент из списка.
Простой пример — Max для чисел типа int. Как мы помним, для конкретных типов интерфейс не так уж и нужен. Пишем реализацию:
int Max(IEnumerable list) { int max = 0; bool first = true; foreach (var x in list) { if (first) { first = false; max = x; } else { if (x > max) max = x; } } if (first) throw new ArgumentException("список пустой!"); return max; }
Это было несложно. Теперь попробуем обобщить этот метод на произвольный тип T. Попробуем обобщить предыдущий метод:
T Max<Т>(IEnumerable list) { T max = default(T); bool first = true; foreach (var x in list) { if (first) { first = false; max = x; } else { if (x > max) max = x; } } if (first) throw new ArgumentException("список пустой!"); return max; }
Получаем ошибку: error CS0019: Operator '>' cannot be applied to operands of type 'T' and 'T'. Потому что компилятор не знает, как ему сравнивать произвольный тип T (и можно ли вообще). Вспоминаем про интерфейс IComparable, и пользуемся им.
Во-первых, мы потребуем, чтобы объекты типа T можно было сравнивать с другими объектами того же типа:
T Max(IEnumerable list) where T : IComparable
Далее, вместо сравнения через > применяем сравнение через IComparable
if (x.CompareTo(max) > 0) max = x;
Пробуем:
int[] list = { 1, 7, 2, 99, -14 }; Console.WriteLine(Max(list));
— получаем на выходе 99.

Заметьте, что если вы определите operator > и operator ==, то этим самым автоматически не будет поддерживаться интерфейс IComparable. Вы должны будете определить его вручную. Можно считать это недостатком в текущей реализации языка.

Дополнительное чтение по теме: Eric Lippert: Double Your Dispatch, Double Your Fun

Комментариев нет:

Отправить комментарий