Как нам уже известно, для сравнения переменных примитивных типов мы можем использовать различные логические операторы. Однако, при написании своих собственных программ мы далеко не всегда используем только примитивные типы данных — мы можем создавать собственные классы с произвольными наборами свойств. И, в этом случае, мы уже не можем просто воспользоваться логическими операторами для сравнения, так как платформа .NET просто не знает как сравнивать произвольные классы (и можно ли их сравнивать, в принципе). Для сравнения двух объектов произвольного типа мы можем, например, воспользоваться возможностью перегрузки операторов, а можем использовать интерфейс IComparable
.
Рабочий пример класса для сравнения
Итак, пусть у нас имеется класс, описывающий обычную коробку:
internal class Box { public int Width { get; set; } public int Height { get; set; } public int Length { get; set; } public int Volume() { return Width * Height * Length; } }
у класса также определен метод Volume
, возвращающий объем нашей коробки. Как определить, что один объект типа Box
больше другого или равен? Условимся, что «больше» будет та коробка у которой больше объем. Теперь попробуем сделать так, чтобы платформа .NET «научилась» сравнивать коробки.
Интерфейс IComparable
Интерфейс IComparable
определяет метод сравнения, который реализуется типом значения или классом для упорядочения или сортировки экземпляров и содержит всего лишь один метод — CompareTo
, который должен возвращать число:
Меньше нуля | Если текущий экземпляр предшествует (меньше) объекта, указанного в методе CompareTo |
Нуль | Если текущий экземпляр находится в том же положении (равен) объекту, указанному в методе CompareTo . |
Больше нуля | Если текущий экземпляр следует за объектом (больше), заданным в методе CompareTo . |
Чаще всего, при реализации метода CompareTo
используются числа 1
, 0
и -1
. Реализуем интерфейс IComparable
в нашем классе Box
:
internal class Box: IComparable { //тут свойства и методы класса public int CompareTo(object? obj) { Box? box = obj as Box; if (box == null) throw new Exception("Невозможно сравнить объекты"); if (this.Volume() > box.Volume()) return 1; if (this.Volume() < box.Volume()) return -1; return 0; } }
Выше приведен подробный код реализации метода CompareTo
. Но, так как результатом метода Volume
является примитивный тип int
, то мы можем написать наш метод намного короче, используя метод CompareTo()
уже реализованный в типе Int
:
public int CompareTo(object? obj) { Box? box = obj as Box; if (box == null) throw new Exception("Невозможно сравнить объекты"); //Используем метод CompareTo у типа Int return Volume().CompareTo(box.Volume()); }
Теперь мы можем сравнивать объекты типа Box
, например:
Box box1 = new Box() { Height = 1, Length = 1, Width = 1 }; Box box2 = new Box() { Height = 2, Length = 2, Width = 1 }; Console.WriteLine($"Объем первой коробки {box1.Volume()}"); Console.WriteLine($"Объем второй коробки {box2.Volume()}"); if (box1.CompareTo(box2) > 0) Console.WriteLine("Первая коробка БОЛЬШЕ второй"); else if (box1.CompareTo(box2) < 0) Console.WriteLine("Первая коробка МЕНЬШЕ второй"); else Console.WriteLine("Первая коробка РАВНА второй");
Объем второй коробки 4
Первая коробка МЕНЬШЕ второй
Интерфейс IComparable<T>
Интерфейс IComparable
имеет также обобщенную версию — IComparable<T>
, используя которую мы можем немного сократить код нашего метода CompareTo
следующим образом:
public int CompareTo(Box? box) { if (box == null) throw new Exception("Невозможно сравнить объекты"); //Используем метод CompareTo у типа Int return Volume().CompareTo(box.Volume()); }
Как можно видеть, метод CompareTo
обобщенной версии интерфейса в качестве параметра принимает объект, типа, указанного в описании, т.е. в нашем случае — типа Box
, что позволяет нам избежать лишнего приведения типов.
Итого
Интерфейс IComparable
предназначен для реализации в классах метода сравнения двух объектов. Этот интерфейс удобно использовать в том случае, если заранее не известно как сравнить два объекта произвольного типа. Обобщенная версия интерфейса — IComparable<T>
позволяет немного упростить код метода CompareTo
.