Сравнение произвольных типов в C#. Интерфейс IComparable

уважаемые посетители блога, если Вам понравилась, то, пожалуйста, помогите автору с лечением. Подробности тут.

Как нам уже известно, для сравнения переменных примитивных типов мы можем использовать различные логические операторы. Однако, при написании своих собственных программ мы далеко не всегда используем только примитивные типы данных — мы можем создавать собственные классы с произвольными наборами свойств. И, в этом случае, мы уже не можем просто воспользоваться логическими операторами для сравнения, так как платформа .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("Первая коробка РАВНА второй");
Объем первой коробки 1
Объем второй коробки 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.

уважаемые посетители блога, если Вам понравилась, то, пожалуйста, помогите автору с лечением. Подробности тут.
Подписаться
Уведомить о
guest
0 Комментарий
Межтекстовые Отзывы
Посмотреть все комментарии