Usare le IComparable interfacce e IComparer in Visual CSharp

Questo articolo descrive l'uso delle IComparer interfacce e IComparable in Visual C#.

Versione originale del prodotto: Oggetto visivo C#
Numero KB originale: 320727

Riepilogo

Le IComparable interfacce e IComparer vengono illustrate nello stesso articolo per due motivi. Queste interfacce vengono spesso usate insieme. Anche se le interfacce sono simili e hanno nomi simili, hanno scopi diversi.

Se si dispone di una matrice di tipi (ad esempio stringa o integer) che supportano IComparergià , è possibile ordinare tale matrice senza fornire alcun riferimento esplicito a IComparer. In tal caso, viene eseguito automaticamente il cast degli elementi della matrice all'implementazione predefinita di IComparer (Comparer.Default). Tuttavia, se si vuole fornire funzionalità di ordinamento o confronto per gli oggetti personalizzati, è necessario implementare una o entrambe queste interfacce.

Questo articolo fa riferimento allo spazio dei nomi System.CollectionsDella libreria di classi di Microsoft .NET Framework.

IComparable

Il ruolo di IComparable consiste nel fornire un metodo per confrontare due oggetti di un tipo specifico. È necessario se si vuole fornire qualsiasi funzionalità di ordinamento per l'oggetto. Si consideri IComparable come un ordinamento predefinito per gli oggetti. Ad esempio, se si dispone di una matrice di oggetti del tipo e si chiama il Sort metodo su tale matrice, IComparable viene fornito il confronto degli oggetti durante l'ordinamento. Quando si implementa l'interfaccia IComparable , è necessario implementare il CompareTo metodo , come indicato di seguito:

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

Il confronto nel metodo è diverso a seconda del tipo di dati del valore confrontato. String.Compare viene utilizzato in questo esempio perché la proprietà scelta per il confronto è una stringa.

IComparer

Il ruolo di IComparer consiste nel fornire più meccanismi di confronto. Ad esempio, è possibile specificare l'ordinamento della classe in più campi o proprietà, in ordine crescente e decrescente nello stesso campo o in entrambi.

L'uso IComparer di è un processo in due passaggi. Dichiarare prima una classe che implementa IComparere quindi implementare il Compare metodo :

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;
   }
}

Nota

Il IComparer.Compare metodo richiede un confronto terziario. Viene restituito 1, 0 o -1 a seconda che un valore sia maggiore, uguale o minore dell'altro. L'ordinamento (crescente o decrescente) può essere modificato cambiando gli operatori logici in questo metodo.

Il secondo passaggio consiste nel dichiarare un metodo che restituisce un'istanza dell'oggetto IComparer :

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

In questo esempio l'oggetto viene utilizzato come secondo argomento quando si chiama il metodo di Array.Sort overload che accetta IComparer. L'uso di IComparer non è limitato alle matrici. Viene accettato come argomento in molte classi di raccolta e controllo diverse.

Esempio dettagliato

Nell'esempio seguente viene illustrato l'uso di queste interfacce. Per illustrare IComparer e IComparable, viene creata una classe denominata Car . L'oggetto Car ha le proprietà make e year. Tramite l'interfaccia IComparable viene abilitato un ordinamento crescente per il campo make e un ordinamento decrescente nel campo make tramite l'interfaccia IComparer . Sia gli ordinamenti crescente che decrescente vengono forniti per la proprietà year usando IComparer.

  1. In Visual C# creare un nuovo progetto applicazione console. Assegnare all'applicazione il nome ConsoleEnum.

  2. Rinominare Program.cs come Host.cs e quindi sostituire il codice con il codice seguente.

    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. Aggiungere una classe al progetto. Assegnare alla classe il nome Car.

  4. Sostituire il codice in Car.cs con il codice seguente:

    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. Eseguire il progetto. Nella finestra Console viene visualizzato l'output seguente:

    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