Файл: Сравнение и сортировка объектов произвольного типа Сравнение произвольных типов в C#. Интерфейс icomparable.docx

ВУЗ: Не указан

Категория: Не указан

Дисциплина: Не указана

Добавлен: 22.11.2023

Просмотров: 20

Скачиваний: 1

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.

Сравнение и сортировка объектов произвольного типа

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

Как нам уже известно, для сравнения переменных примитивных типов мы можем использовать различные логические операторы. Однако, при написании своих собственных программ мы далеко не всегда используем только примитивные типы данных – мы можем создавать собственные классы с произвольными наборами свойств. И, в этом случае, мы уже не можем просто воспользоваться логическими операторами для сравнения, так как платформа .NET просто не знает, как сравнивать произвольные классы (и можно ли их сравнивать, в принципе). Для сравнения двух объектов произвольного типа мы можем, например, воспользоваться возможностью перегрузки операторов, а можем использовать интерфейс IComparable.

Пример класса для сравнения.


Пусть у нас имеется класс, описывающий обычную коробку:

class Box

{

public double Width { get; set; }

public double Height { get; set; }

public double Length { get; set; }
public double Volume()

{

return Width * Height * Length;

}

}

У класса также определен метод Volume, возвращающий объем нашей коробки. Как определить, что один объект типа Box больше другого или равен? Условимся, что «больше» будет та коробка, у которой больше объем. Теперь попробуем сделать так, чтобы платформа .NET «научилась» сравнивать коробки.

Интерфейс IComparable

Интерфейс IComparable определяет метод сравнения, который реализуется типом значения или классом для упорядочения или сортировки экземпляров и содержит всего лишь один метод – CompareTo, который должен возвращать число:

Меньше нуля

Если текущий экземпляр предшествует (меньше) объекта, указанного в методе CompareTo

Нуль

Если текущий экземпляр находится в том же положении (равен) объекту, указанному в методе CompareTo.

Больше нуля

Если текущий экземпляр следует за объектом (больше), заданным в методе CompareTo.

Чаще всего, при реализации метода CompareTo используются числа 1, 0 и -1. Реализуем интерфейс IComparable в нашем классе Box:

class Box: IComparable

{

public double Width { get; set; }

public double Height { get; set; }


public double Length { get; set; }
public double Volume()

{

return Width * Height * Length;

}
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 является примитивный тип double, то мы можем написать наш метод намного короче, используя метод CompareTo() уже реализованный в типе double:

public int CompareTo(object obj)

{

Box box = obj as Box;

if (box == null)

throw new Exception("Невозможно сравнить объекты");

return Volume().CompareTo(box.Volume());

}

Теперь мы можем сравнивать объекты типа Box, например:

class Program

{

static void Main(string[] args)

{

Box box1 = new Box() { Height = 1, Length = 1, Width = 1 };

Box box2 = new Box() { Height = 2, Length = 2, Width = 1 };

Console.WriteLine("Объем первой коробки {0}", box1.Volume());

Console.WriteLine("Объем второй коробки {0}", box2.Volume());

if (box1.CompareTo(box2) > 0)

Console.WriteLine("Первая коробка БОЛЬШЕ второй");

else

if (box1.CompareTo(box2) < 0)

Console.WriteLine("Первая коробка МЕНЬШЕ второй");

else

Console.WriteLine("Первая коробка РАВНА второй");

Console.ReadLine();

}

}

Результат работы программы:

Объем первой коробки 1

Объем второй коробки 4

Первая коробка МЕНЬШЕ второй

Интерфейс IComparable

Интерфейс IComparable имеет также обобщенную версию – IComparable, используя которую мы можем немного сократить код нашего метода CompareTo следующим образом:

class Box : IComparable

{

... // свойства и методы класса
public int CompareTo(Box box)

{

if (box == null)

throw new Exception("Невозможно сравнить объекты");

//Используем метод CompareTo у типа double

return Volume().CompareTo(box.Volume());

}

}

Как можно видеть, метод CompareTo обобщенной версии интерфейса в качестве параметра принимает объект, типа, указанного в описании, т.е. в нашем случае – типа Box, что позволяет нам избежать лишнего приведения типов.

Итог

Интерфейс IComparable предназначен для реализации в классах метода сравнения двух объектов. Этот интерфейс удобно использовать в том случае, если заранее не известно, как сравнить два объекта произвольного типа. Обобщенная версия интерфейса —IComparable позволяет немного упростить код метода CompareTo.

Сортировка объектов произвольного типа. Интерфейс IComparer

Для чего нужен интерфейс IComparer

У обобщенного списка List определено несколько перегруженных методов Sort, позволяющих производить сортировку элементов списка. В прошлой части мы реализовали интерфейс IComparable для класса Box (коробка). Создадим несколько объектов типа Box, поместим их в список и попробуем воспользоваться методом Sort:

class Program

{

static void Main(string[] args)

{

List boxes = new List()

{

new Box(){Height = 2, Length = 2, Width = 2 },//Объем 8

new Box(){Height = 1, Length = 1, Width = 1 },//Объем 1

new Box(){Height = 3, Length = 3, Width = 3 },//Объем 27

new Box(){Height = 4, Length = 4, Width = 4 } //Объем 64

};

boxes.Sort();

foreach (Box box in boxes)

{

Console.WriteLine("Длина {0} Ширина {1} Высота {2} Объем {3}",

box.Length, box.Width, box.Height, box.Volume());

}

Console.ReadLine();

}

}

Так как наш класс реализует интерфейс IComparable, то платформа .NET «понимает» как сравнивать два объекта типа Box между собой и, поэтому, результат сортировки будет вполне ожидаемым – все коробки отсортируются по их объему:

Длина 1 Ширина 1 Высота 1 Объем 1

Длина 2 Ширина 2 Высота 2 Объем 8

Длина 3 Ширина 3 Высота 3 Объем 27

Длина 4 Ширина 4 Высота 4 Объем 64

Но что, если нам потребуется провести сортировку наших коробок не по объему, а, например, по их длине? Каждый раз переписывать реализацию метода CompareTo – не вариант. В этом случае нам поможет интерфейс IComparer, реализуя который в классе мы можем впоследствии переопределять метод сортировки в списке List (или другой коллекции).

Интерфейс IComparer

Интерфейс IComparer определяет метод Compare, с помощью которого проводится сравнение двух элементов. Как и в случае с методом CompareTo, метод Compare возвращает три значения:

Меньше нуля

Если левый элемент предшествует (меньше) правого, указанного в методе Compare

Нуль

Если элементы равны

Больше нуля

Если левый элемент следует за объектом (больше), заданным в методе Compare

Попробуем реализовать метод сортировки коробок по их длине. Для этого создадим новый класс BoxComparer и реализуем в нем интерфейс IComparer:

class BoxComparer : IComparer

{

public int Compare(Box x, Box y)

{

if ((x == null) || (y == null))

throw new Exception("Невозможно сравнить элементы");

return Math.Sign(x.Length - y.Length);

}

}

Теперь можем воспользоваться нашим классом-компаратором и отсортировать коробки по длине:

List boxes = new List()

{

new Box(){Height = 3, Length = 2, Width = 8 },

new Box(){Height = 1, Length = 1, Width = 1 },

new Box(){Height = 5, Length = 3, Width = 4 },

new Box(){Height = 1, Length = 4, Width = 1 }

};

boxes.Sort(new BoxComparer());

foreach (Box box in boxes)

{

Console.WriteLine("Длина {0} Ширина {1} Высота {2} Объем {3}",

box.Length, box.Width, box.Height, box.Volume());

}

Результат:

Длина 1 Ширина 1 Высота 1 Объем 1

Длина 2 Ширина 8 Высота 3 Объем 48

Длина 3 Ширина 4 Высота 5 Объем 60

Длина 4 Ширина 1 Высота 1 Объем 4

Используя класс BoxComparer, мы можем реализовать в нем разные методы сортировки, но, при этом, метод Compare должен быть одним. Например, реализуем сортировку по возрастанию и убыванию длины:

class BoxComparer : IComparer

{

private bool ascSort = true;

public bool AscSort

{

get { return ascSort; }

set { ascSort = value; }

}

public int Compare(Box x, Box y)

{

if ((x == null) || (y == null))

throw new Exception("Невозможно сравнить элементы");

if (AscSort)

return Math.Sign(x.Length - y.Length);

else

return Math.Sign(y.Length - x.Length);

}

}

Мы добавили свойство AscSort, указывающее на то, как сортировать список. Пример использования:

class Program

{

static void Main(string[] args)

{

List boxes = new List()

{

new Box(){Height = 3, Length = 2, Width = 8 },

new Box(){Height = 1, Length = 1, Width = 1 },

new Box(){Height = 5, Length = 3, Width = 4 },

new Box(){Height = 1, Length = 4, Width = 1 }

};

Console.WriteLine("Сортировка коробок по ВОЗРАСТАНИЮ длины");

boxes.Sort(new BoxComparer());

foreach (Box box in boxes)

{

Console.WriteLine("Длина {0} Ширина {1} Высота {2} Объем {3}",

box.Length, box.Width, box.Height, box.Volume());

}

Console.WriteLine("Сортировка коробок по УБЫВАНИЮ длины");

boxes.Sort(new BoxComparer() { AscSort = false });

foreach (Box box in boxes)

{

Console.WriteLine("Длина {0} Ширина {1} Высота {2} Объем {3}",

box.Length, box.Width, box.Height, box.Volume());

}

Console.ReadLine();

}

}

Результат:

Сортировка коробок по ВОЗРАСТАНИЮ длины

Длина 1 Ширина 1 Высота 1 Объем 1

Длина 2 Ширина 8 Высота 3 Объем 48

Длина 3 Ширина 4 Высота 5 Объем 60

Длина 4 Ширина 1 Высота 1 Объем 4

Сортировка коробок по УБЫВАНИЮ длины

Длина 4 Ширина 1 Высота 1 Объем 4

Длина 3 Ширина 4 Высота 5 Объем 60

Длина 2 Ширина 8 Высота 3 Объем 48

Длина 1 Ширина 1 Высота 1 Объем 1

Итог

Интерфейс IComparer позволяет переопределить способ сортировки элементов коллекции. Для сортировки элементов коллекции, объекты должны реализовывать интерфейс IComparable, который устанавливает правила сравнения двух элементов (метод CompareTo). Если у коллекции вызывается метод Sort() без параметров, то используется метод сравнения по умолчанию, т.е. CompareTo. Интерфейс же IComparer позволяет создать свою логику сравнения и сортировки объектов произвольного типа, отличную от реализованной в методе CompareTo.
Интернет-источники


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

https://csharp.webdelphi.ru/sravnenie-proizvolnyx-tipov-v-c-interfejs-icomparable/

  1. Сортировка объектов произвольного типа. Интерфейс IComparer

https://csharp.webdelphi.ru/sortirovka-obektov-proizvolnogo-tipa-interfejs-icomparer/