IComparable Использование интерфейсов и IComparer в Visual CSharp

В этой статье описывается использование интерфейсов IComparer и IComparable в Visual C#.

Исходная версия продукта: Visual C#
Исходный номер базы знаний: 320727

Сводка

Интерфейсы IComparable и IComparer рассматриваются в одной статье по двум причинам. Эти интерфейсы часто используются вместе. Хотя интерфейсы похожи и имеют похожие имена, они служат для разных целей.

Если у вас есть массив типов (например, string или integer), которые уже поддерживают IComparer, вы можете сортировать этот массив, не указывая явных ссылок на IComparer. В этом случае элементы массива будут приведены к реализации IComparer по умолчанию (Comparer.Default). Однако если вы хотите предоставить возможность сортировки или сравнения для пользовательских объектов, необходимо реализовать один из этих интерфейсов или оба этих интерфейса.

В этой статье содержится ссылка на пространство System.Collectionsимен библиотеки классов Microsoft платформа .NET Framework .

IComparable

Роль IComparable заключается в предоставлении метода сравнения двух объектов определенного типа. Это необходимо, если вы хотите предоставить возможность упорядочивания для объекта. Подумайте о том, как предоставить порядок сортировки IComparable по умолчанию для объектов. Например, если у вас есть массив объектов вашего типа и вы вызываете Sort метод в этом массиве, IComparable выполняется сравнение объектов во время сортировки. При реализации IComparable интерфейса необходимо реализовать CompareTo метод следующим образом:

// Implement IComparable CompareTo method - provide default sort order.
int IComparable.CompareTo(object obj)
{
   Car c=(Car)obj;
   return String.Compare(this.make,c.make);
}

Сравнение в методе отличается в зависимости от типа данных сравниваемого значения. String.Compare используется в этом примере, так как свойство, выбранное для сравнения, является строкой.

IComparer

Роль заключается в предоставлении дополнительных IComparer механизмов сравнения. Например, может потребоваться упорядочение класса по нескольким полям или свойствам, по возрастанию и убыванию одного и того же поля или по обоим полям.

Использование IComparer — это двухэтапный процесс. Сначала объявите класс, реализующий IComparer, а затем реализуйте Compare метод :

private class SortYearAscendingHelper : IComparer
{
   int IComparer.Compare(object a, object b)
   {
      Car c1=(Car)a;
      Car c2=(Car)b;
      if (c1.year > c2.year)
         return 1;
      if (c1.year < c2.year)
         return -1;
      else
         return 0;
   }
}

Примечание.

Для IComparer.Compare метода требуется третичное сравнение. Значение 1, 0 или -1 возвращается в зависимости от того, больше ли одно значение, равно или меньше другого. Порядок сортировки (по возрастанию или убыванию) можно изменить путем переключения логических операторов в этом методе.

Второй шаг заключается в объявлении метода, который возвращает экземпляр объекта IComparer :

public static IComparer SortYearAscending()
{
   return (IComparer) new SortYearAscendingHelper();
}

В этом примере объект используется в качестве второго аргумента при вызове перегруженного Array.Sort метода, который принимает IComparer. Использование IComparer не ограничивается массивами. Он принимается в качестве аргумента во многих различных классах коллекций и элементов управления.

Пошаговый пример

В следующем примере показано использование этих интерфейсов. Для демонстрации IComparer и IComparableсоздается класс с именем Car . Объект Car имеет свойства make и year. Сортировка по возрастанию для поля make включается через IComparable интерфейс, а сортировка по убыванию в поле make включается через IComparer интерфейс . Сортировка по возрастанию и убыванию предоставляется для свойства year с помощью IComparer.

  1. В Visual C# создайте проект консольного приложения. Присвойтите приложению имя ConsoleEnum.

  2. Переименуйте Program.cs как Host.cs, а затем замените код следующим кодом.

    using System;
    
    namespace ConsoleEnum
    {
        class host
        {
           [STAThread]
           static void Main(string[] args)
           {
              // Create an array of Car objects.
              Car[] arrayOfCars= new Car[6]
              {
                 new Car("Ford",1992),
                 new Car("Fiat",1988),
                 new Car("Buick",1932),
                 new Car("Ford",1932),
                 new Car("Dodge",1999),
                 new Car("Honda",1977)
              };
    
              // Write out a header for the output.
              Console.WriteLine("Array - Unsorted\n");
    
              foreach(Car c in arrayOfCars)
                 Console.WriteLine(c.Make + "\t\t" + c.Year);
    
              // Demo IComparable by sorting array with "default" sort order.
              Array.Sort(arrayOfCars);
              Console.WriteLine("\nArray - Sorted by Make (Ascending - IComparable)\n");
    
              foreach(Car c in arrayOfCars)
                 Console.WriteLine(c.Make + "\t\t" + c.Year);
    
              // Demo ascending sort of numeric value with IComparer.
              Array.Sort(arrayOfCars,Car.SortYearAscending());
              Console.WriteLine("\nArray - Sorted by Year (Ascending - IComparer)\n");
    
              foreach(Car c in arrayOfCars)
                 Console.WriteLine(c.Make + "\t\t" + c.Year);
    
              // Demo descending sort of string value with IComparer.
              Array.Sort(arrayOfCars,Car.SortMakeDescending());
              Console.WriteLine("\nArray - Sorted by Make (Descending - IComparer)\n");
    
              foreach(Car c in arrayOfCars)
                 Console.WriteLine(c.Make + "\t\t" + c.Year);
    
              // Demo descending sort of numeric value using IComparer.
              Array.Sort(arrayOfCars,Car.SortYearDescending());
              Console.WriteLine("\nArray - Sorted by Year (Descending - IComparer)\n");
    
              foreach(Car c in arrayOfCars)
                 Console.WriteLine(c.Make + "\t\t" + c.Year);
    
              Console.ReadLine();
           }
       }
    }
    
  3. Добавьте класс в проект. Назовите класс Car.

  4. Замените код в Car.cs следующим кодом:

    using System;
    using System.Collections;
    namespace ConsoleEnum
    {
       public class Car : IComparable
       {
          // Beginning of nested classes.
          // Nested class to do ascending sort on year property.
          private class SortYearAscendingHelper: IComparer
          {
             int IComparer.Compare(object a, object b)
             {
                Car c1=(Car)a;
                Car c2=(Car)b;
    
                if (c1.year > c2.year)
                   return 1;
    
                if (c1.year < c2.year)
                   return -1;
    
                else
                   return 0;
             }
          }
    
          // Nested class to do descending sort on year property.
          private class SortYearDescendingHelper: IComparer
          {
             int IComparer.Compare(object a, object b)
             {
                Car c1=(Car)a;
                Car c2=(Car)b;
    
                if (c1.year < c2.year)
                   return 1;
    
                if (c1.year > c2.year)
                   return -1;
    
                else
                   return 0;
             }
          }
    
          // Nested class to do descending sort on make property.
          private class SortMakeDescendingHelper: IComparer
          {
             int IComparer.Compare(object a, object b)
             {
                Car c1=(Car)a;
                Car c2=(Car)b;
                 return String.Compare(c2.make,c1.make);
             }
          }
          // End of nested classes.
          private int year;
          private string make;
    
          public Car(string Make,int Year)
          {
             make=Make;
             year=Year;
          }
    
          public int Year
          {
             get  {return year;}
             set {year=value;}
          }
    
          public string Make
          {
             get {return make;}
             set {make=value;}
          }
          // Implement IComparable CompareTo to provide default sort order.
          int IComparable.CompareTo(object obj)
          {
             Car c=(Car)obj;
             return String.Compare(this.make,c.make);
          }
          // Method to return IComparer object for sort helper.
          public static IComparer SortYearAscending()
          {
             return (IComparer) new SortYearAscendingHelper();
          }
          // Method to return IComparer object for sort helper.
          public static IComparer SortYearDescending()
          {
             return (IComparer) new SortYearDescendingHelper();
          }
          // Method to return IComparer object for sort helper.
          public static IComparer SortMakeDescending()
          {
            return (IComparer) new SortMakeDescendingHelper();
          }
    
       }
    }
    
  5. Запустите проект. В окне консоли отображаются следующие выходные данные:

    Array - Unsorted
    
    Ford 1992
    Fiat 1988
    Buick 1932
    Ford 1932
    Dodge 1999
    Honda 1977
    
    Array - Sorted by Make (Ascending - IComparable)
    
    Buick 1932
    Dodge 1999
    Fiat 1988
    Ford 1932
    Ford 1992
    Honda 1977
    
    Array - Sorted by Year (Ascending - IComparer)
    
    Ford 1932
    Buick 1932
    Honda 1977
    Fiat 1988
    Ford 1992
    Dodge 1999
    
    Array - Sorted by Make (Descending - IComparer)
    
    Honda 1977
    Ford 1932
    Ford 1992
    Fiat 1988
    Dodge 1999
    Buick 1932
    
    Array - Sorted by Year (Descending - IComparer)
    
    Dodge 1999
    Ford 1992
    Fiat 1988
    Honda 1977
    Buick 1932
    Ford 1932