0Pricing
C# Academy · Урок

Реализация IComparable

Определяйте естественный порядок сортировки с помощью CompareTo.

«Реализация IComparable» — бесплатный урок C# Academy на CoddyKit. Это урок 3 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения C# Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс C# Academy содержит 4 уроков всего.

Упорядочивание с помощью IComparable<T>

IComparable<T> определяет естественный порядок типа с помощью одного метода — CompareTo. После реализации ваш тип можно сортировать с помощью Array.Sort, List.Sort и упорядоченных коллекций.

Контракт CompareTo

CompareTo возвращает отрицательное число, если этот экземпляр меньше другого, ноль — если они равны, и положительное число — если он больше. Сравнение базовых значений часто позволяет реализовать это напрямую.

using System;

public struct Weight : IComparable<Weight>
{
    public int Grams;
    public Weight(int g) { Grams = g; }

    public int CompareTo(Weight other) => Grams.CompareTo(other.Grams);

    public override string ToString() => Grams + "g";
}

public class Program
{
    public static void Main()
    {
        Console.WriteLine(new Weight(100).CompareTo(new Weight(200)));
        Console.WriteLine(new Weight(200).CompareTo(new Weight(200)));
        Console.WriteLine(new Weight(300).CompareTo(new Weight(200)));
    }
}

Сортировка списка

После того как тип становится сопоставимым, List<T>.Sort() упорядочивает его с помощью CompareTo без дополнительных аргументов.

using System;
using System.Collections.Generic;

public struct Weight : IComparable<Weight>
{
    public int Grams;
    public Weight(int g) { Grams = g; }
    public int CompareTo(Weight other) => Grams.CompareTo(other.Grams);
    public override string ToString() => Grams + "g";
}

public class Program
{
    public static void Main()
    {
        var list = new List<Weight> { new Weight(300), new Weight(100), new Weight(200) };
        list.Sort();
        Console.WriteLine(string.Join(", ", list));
    }
}

Сравнение по основному полю

Для класса выберите поле, определяющее его естественный порядок. Здесь элементы people упорядочиваются по возрасту с делегированием сравнения методу int.CompareTo.

using System;
using System.Collections.Generic;

public class Person : IComparable<Person>
{
    public string Name;
    public int Age;
    public Person(string name, int age) { Name = name; Age = age; }
    public int CompareTo(Person other) => Age.CompareTo(other.Age);
    public override string ToString() => Name + "(" + Age + ")";
}

public class Program
{
    public static void Main()
    {
        var people = new List<Person> { new Person("Ann", 30), new Person("Bo", 20) };
        people.Sort();
        Console.WriteLine(string.Join(", ", people));
    }
}

Разрешение совпадений по нескольким полям

Если значения первичного ключа совпадают, сравнивайте вторичное поле. Выполните первое сравнение и только при результате, равном нулю, переходите к следующему.

using System;
using System.Collections.Generic;

public class Person : IComparable<Person>
{
    public string Name;
    public int Age;
    public Person(string name, int age) { Name = name; Age = age; }
    public int CompareTo(Person other)
    {
        int byAge = Age.CompareTo(other.Age);
        return byAge != 0 ? byAge : string.Compare(Name, other.Name, StringComparison.Ordinal);
    }
    public override string ToString() => Name + "(" + Age + ")";
}

public class Program
{
    public static void Main()
    {
        var people = new List<Person> { new Person("Zoe", 30), new Person("Ann", 30) };
        people.Sort();
        Console.WriteLine(string.Join(", ", people));
    }
}

Сортировка массивов

Array.Sort также использует IComparable<T>. Одна и та же логика сравнения работает для массивов, списков и упорядоченных структур.

using System;

public struct Score : IComparable<Score>
{
    public int Points;
    public Score(int p) { Points = p; }
    public int CompareTo(Score other) => Points.CompareTo(other.Points);
    public override string ToString() => Points.ToString();
}

public class Program
{
    public static void Main()
    {
        var scores = new[] { new Score(50), new Score(10), new Score(30) };
        Array.Sort(scores);
        Console.WriteLine(string.Join(", ", (object[])scores));
    }
}

Сортировка по убыванию

Чтобы изменить порядок, инвертируйте сравнение, поменяв местами операнды CompareTo. Это удобный способ сортировать от большего к меньшему без отдельного средства сравнения.

using System;
using System.Collections.Generic;

public struct Score : IComparable<Score>
{
    public int Points;
    public Score(int p) { Points = p; }
    // Reversed: higher points come first
    public int CompareTo(Score other) => other.Points.CompareTo(Points);
    public override string ToString() => Points.ToString();
}

public class Program
{
    public static void Main()
    {
        var list = new List<Score> { new Score(10), new Score(50), new Score(30) };
        list.Sort();
        Console.WriteLine(string.Join(", ", list));
    }
}

Сопоставимость и равенство вместе

Если CompareTo возвращает ноль, элементы считаются равными с точки зрения порядка. Согласуйте это поведение с Equals, чтобы сортировка и проверка равенства не противоречили друг другу.

using System;

public struct Version : IComparable<Version>, IEquatable<Version>
{
    public int Major, Minor;
    public Version(int major, int minor) { Major = major; Minor = minor; }
    public int CompareTo(Version other)
    {
        int byMajor = Major.CompareTo(other.Major);
        return byMajor != 0 ? byMajor : Minor.CompareTo(other.Minor);
    }
    public bool Equals(Version other) => CompareTo(other) == 0;
    public override bool Equals(object obj) => obj is Version v && Equals(v);
    public override int GetHashCode() => HashCode.Combine(Major, Minor);
}

public class Program
{
    public static void Main()
    {
        Console.WriteLine(new Version(1, 2).CompareTo(new Version(1, 5)));
        Console.WriteLine(new Version(2, 0).Equals(new Version(2, 0)));
    }
}

Использование сравнения в LINQ OrderBy

Даже без сортировки на месте LINQ OrderBy может использовать ваш сопоставимый тип через селектор ключа, лениво создавая отсортированное представление.

using System;
using System.Collections.Generic;
using System.Linq;

public struct Weight : IComparable<Weight>
{
    public int Grams;
    public Weight(int g) { Grams = g; }
    public int CompareTo(Weight other) => Grams.CompareTo(other.Grams);
    public override string ToString() => Grams + "g";
}

public class Program
{
    public static void Main()
    {
        var items = new List<Weight> { new Weight(300), new Weight(100) };
        foreach (var w in items.OrderBy(x => x))
            Console.WriteLine(w);
    }
}

Сортируемый тип предметной области

Реализация IComparable<T> превращает понятие предметной области в нечто, что весь фреймворк может упорядочивать. Здесь tasks сортируются сначала по приоритету, затем по имени.

using System;
using System.Collections.Generic;

public class TaskItem : IComparable<TaskItem>
{
    public string Name;
    public int Priority;
    public TaskItem(string name, int priority) { Name = name; Priority = priority; }
    public int CompareTo(TaskItem other)
    {
        int byPriority = Priority.CompareTo(other.Priority);
        return byPriority != 0 ? byPriority : string.Compare(Name, other.Name, StringComparison.Ordinal);
    }
    public override string ToString() => Priority + ":" + Name;
}

public class Program
{
    public static void Main()
    {
        var tasks = new List<TaskItem>
        {
            new TaskItem("deploy", 2), new TaskItem("build", 1), new TaskItem("test", 1)
        };
        tasks.Sort();
        Console.WriteLine(string.Join(", ", tasks));
    }
}

Попробуйте сами

Создайте сопоставимый тип с несколькими полями и отсортируйте список таких объектов. Естественный порядок определяется через CompareTo без дополнительных аргументов.

using System;
using System.Collections.Generic;

public class Card : IComparable<Card>
{
    public int Rank;
    public string Suit;
    public Card(int rank, string suit) { Rank = rank; Suit = suit; }
    public int CompareTo(Card other)
    {
        int byRank = Rank.CompareTo(other.Rank);
        return byRank != 0 ? byRank : string.Compare(Suit, other.Suit, StringComparison.Ordinal);
    }
    public override string ToString() => Rank + Suit;
}

public class Program
{
    public static void Main()
    {
        var hand = new List<Card>
        {
            new Card(10, "H"), new Card(2, "S"), new Card(10, "C")
        };
        hand.Sort();
        Console.WriteLine(string.Join(", ", hand));
    }
}

Быстрая проверка

Вспомните контракт CompareTo.

Повторение

IComparable<T> задаёт естественный порядок через CompareTo.

  • Отрицательное, нулевое и положительное значения означают соответственно меньше, равно и больше.
  • Это позволяет использовать List.Sort, Array.Sort и упорядоченные коллекции.
  • При совпадении сравнивайте вторичные поля.
  • Следите, чтобы CompareTo == 0 соответствовало Equals.

Часто задаваемые вопросы

Урок «Реализация IComparable» бесплатный?

Да — полный текст урока «Реализация IComparable» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс C# Academy, подпишись на CoddyKit PRO. Курс C# Academy содержит 4 уроков всего.

Чему я научусь в уроке «Реализация IComparable»?

Определяйте естественный порядок сортировки с помощью CompareTo. Ты практикуешь C# Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать C# Academy?

Предыдущий опыт не требуется. C# Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 3 из 4.

Сколько времени занимает урок «Реализация IComparable»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке C# Academy?

Да. Каждый урок C# Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Реализация IEquatable
  2. Переопределение GetHashCode
  3. Реализация IComparable
  4. IComparer для пользовательской сортировки
← Назад к C# Academy