[譯]在C#中使用IComparable和IComparer接口

原文:Use the IComparable and IComparer interfaces in Visual CSharp

本文介紹了在Visual C#中如何使用IComparer和IComparable接口。

概要

本文同時討論了IComparable和IComparer接口,原因有兩點。這兩個接口經常一起使用。雖然接口類似且名稱相似,但它們卻有不同的用途。

如果你有一個支持IComparer的類型數組(例如字符串或整數),你可以對它進行排序而不需要提供任何對IComparer的顯式引用(譯註:意思是把一個IComparer的實現類作爲參數傳遞給排序方法)。在這種情況下,數組元素會被轉換爲IComparer的默認實現(Comparer.Default)。然而,如果你想爲自定義對象提供排序或比較能力,你必須實現這兩個接口中的一個或兩個。

本文引用了Microsoft .NET Framework類庫命名空間System.Collections。

IComparable 接口

IComparable 接口的作用是提供一種比較特定類型的兩個對象的方法。如果你想爲你的對象提供任何排序能力,那麼這是必須的。可以將 IComparable 視爲爲你的對象提供默認的排序順序。例如,如果你有一個對象類型的數組,然後你在該數組上調用 Sort 方法,則排序期間的對象比較是由 IComparable 提供的。當你實現 IComparable 接口時,必須實現 CompareTo 方法,如下所示:

// IComparable 的 CompareTo 方法,提供默認的排序。
int IComparable.CompareTo(object obj)
{
   Car c=(Car)obj;
   return String.Compare(this.make,c.make);
}

CompareTo 方法中如何進行比較取決於被比較值的數據類型。在本例中使用 String.Compare方法,因爲被選擇用於比較的屬性是字符串。

IComparer 接口

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的類,該類擁有Make和Year兩個屬性。通過IComparable接口,爲Make字段啓用了升序排序;通過IComparer接口,爲Make字段啓用了降序排序。通過使用IComparer,爲Year屬性提供了升序和降序排序。

1. 在Visual Studio中創建一個新的Console Application項目,把它命名爲ConsoleEnum。

2. 將Program.cs重命名爲Host.cs,然後用以下代碼替換原有代碼。

 1 using System;
 2 
 3 namespace ConsoleEnum
 4 {
 5     class host
 6     {
 7        [STAThread]
 8        static void Main(string[] args)
 9        {
10           // Create an array of Car objects.
11           Car[] arrayOfCars= new Car[6]
12           {
13              new Car("Ford",1992),
14              new Car("Fiat",1988),
15              new Car("Buick",1932),
16              new Car("Ford",1932),
17              new Car("Dodge",1999),
18              new Car("Honda",1977)
19           };
20 
21           // Write out a header for the output.
22           Console.WriteLine("Array - Unsorted\n");
23 
24           foreach(Car c in arrayOfCars)
25              Console.WriteLine(c.Make + "\t\t" + c.Year);
26 
27           // Demo IComparable by sorting array with "default" sort order.
28           Array.Sort(arrayOfCars);
29           Console.WriteLine("\nArray - Sorted by Make (Ascending - IComparable)\n");
30 
31           foreach(Car c in arrayOfCars)
32              Console.WriteLine(c.Make + "\t\t" + c.Year);
33 
34           // Demo ascending sort of numeric value with IComparer.
35           Array.Sort(arrayOfCars,Car.SortYearAscending());
36           Console.WriteLine("\nArray - Sorted by Year (Ascending - IComparer)\n");
37 
38           foreach(Car c in arrayOfCars)
39              Console.WriteLine(c.Make + "\t\t" + c.Year);
40 
41           // Demo descending sort of string value with IComparer.
42           Array.Sort(arrayOfCars,Car.SortMakeDescending());
43           Console.WriteLine("\nArray - Sorted by Make (Descending - IComparer)\n");
44 
45           foreach(Car c in arrayOfCars)
46              Console.WriteLine(c.Make + "\t\t" + c.Year);
47 
48           // Demo descending sort of numeric value using IComparer.
49           Array.Sort(arrayOfCars,Car.SortYearDescending());
50           Console.WriteLine("\nArray - Sorted by Year (Descending - IComparer)\n");
51 
52           foreach(Car c in arrayOfCars)
53              Console.WriteLine(c.Make + "\t\t" + c.Year);
54 
55           Console.ReadLine();
56        }
57    }
58 }

3. 在項目中新增一個類,命名爲Car。

4. 用下面的代碼替換Car.cs中的代碼。

  1 using System;
  2 using System.Collections;
  3 namespace ConsoleEnum
  4 {
  5    public class Car : IComparable
  6    {
  7       // Beginning of nested classes.
  8       // Nested class to do ascending sort on year property.
  9       private class SortYearAscendingHelper: IComparer
 10       {
 11          int IComparer.Compare(object a, object b)
 12          {
 13             Car c1=(Car)a;
 14             Car c2=(Car)b;
 15 
 16             if (c1.year > c2.year)
 17                return 1;
 18 
 19             if (c1.year < c2.year)
 20                return -1;
 21 
 22             else
 23                return 0;
 24          }
 25       }
 26 
 27       // Nested class to do descending sort on year property.
 28       private class SortYearDescendingHelper: IComparer
 29       {
 30          int IComparer.Compare(object a, object b)
 31          {
 32             Car c1=(Car)a;
 33             Car c2=(Car)b;
 34 
 35             if (c1.year < c2.year)
 36                return 1;
 37 
 38             if (c1.year > c2.year)
 39                return -1;
 40 
 41             else
 42                return 0;
 43          }
 44       }
 45 
 46       // Nested class to do descending sort on make property.
 47       private class SortMakeDescendingHelper: IComparer
 48       {
 49          int IComparer.Compare(object a, object b)
 50          {
 51             Car c1=(Car)a;
 52             Car c2=(Car)b;
 53              return String.Compare(c2.make,c1.make);
 54          }
 55       }
 56       // End of nested classes.
 57       private int year;
 58       private string make;
 59 
 60       public Car(string Make,int Year)
 61       {
 62          make=Make;
 63          year=Year;
 64       }
 65 
 66       public int Year
 67       {
 68          get  {return year;}
 69          set {year=value;}
 70       }
 71 
 72       public string Make
 73       {
 74          get {return make;}
 75          set {make=value;}
 76       }
 77       // Implement IComparable CompareTo to provide default sort order.
 78       int IComparable.CompareTo(object obj)
 79       {
 80          Car c=(Car)obj;
 81          return String.Compare(this.make,c.make);
 82       }
 83       // Method to return IComparer object for sort helper.
 84       public static IComparer SortYearAscending()
 85       {
 86          return (IComparer) new SortYearAscendingHelper();
 87       }
 88       // Method to return IComparer object for sort helper.
 89       public static IComparer SortYearDescending()
 90       {
 91          return (IComparer) new SortYearDescendingHelper();
 92       }
 93       // Method to return IComparer object for sort helper.
 94       public static IComparer SortMakeDescending()
 95       {
 96         return (IComparer) new SortMakeDescendingHelper();
 97       }
 98 
 99    }
100 }

5. 運行項目。Console窗口顯示如下:

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

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章