在項目中經常會用到字符串比較,但是有時候對字符串的操作比較多,規則各異。比如有的地方我們需要用排序規則,有的地方需要忽略大小寫,我們該如何寫一個比較容易操作的比較方法呢?重新實現IComparer接口不失為一個好辦法。
IComparable.CompareTo 方法
在MSDN上是這么解釋(機器翻譯過來)的:
IComparable接口:定義一種特定於類型的通用比較方法,值類型或類通過實現此方法對其實例進行排序。
IComparer接口:公開一種比較兩個對象的方法。
詳細理解就是:
在默認情況下,對象的Equals(object o)方法(基類Object提供),是比較兩個對象變量是否引用同一對象。
我們要必須我們自己的對象,必須自己定義對象比較方式。
IComparable和ICompare 接口是.net framework 中比較對象的標准方式,這兩個接口之間的區別如下:
IComparable是標識這個類型具有比較的能力,可以比較該對象和另一個對象。一般情況下,我們使用 IComparable 給出類的默認比較代碼,使用其他類給出非默認的比較代碼。中文應該叫“可比較對象”。
IComparer是在一個單獨的類中實現,是指當前對象可以用來比較任意兩個對象,而當前對象本身不參與計算,中文應該叫“比較器”。
CompareTo:IComparable提供了一個方法int CompareTo(object obj)。這個方法接受一個對象,將當前實例的對象與同一類型的另一個對象進行比較,並返回一個整數,該整數指示當前實例在排序順序中的位置是位於另一個對象之前、之后還是與其位置相同。
Compare:IComparer 也提供了一個方法 Compare().這個方法接受兩個對象,返回一個整型結果,這與 CompareTo()相同。
IComparable接口
比如:有一個默認實例對象person1,需要和person2判斷,判斷person1是否比person2更年老或年輕,實際上,這個方法返回一個int,所以可和下面的代碼說明person1更年老還是更年輕。
1 if(person1.CompareTo(person2) == 0) 2 { 3 Console.WriteLine("Same age");//年齡一樣,person1和person2比較后返回0 4 } 5 else if(person1.CompareTo(person2) > 0 ) 6 { 7 Console.WriteLine("person1 is older");//如果person1>person2,person1和person2比較后返回正整數,person1比person2年齡大 8 } 9 else 10 { 11 Console.WriteLine("person1 is younger");//如上述if不成立,person1<person2,person1和person2比較后返回正整數,person1比person2年齡小 12 }
IComparer接口
同樣適用person來做例子
比如:有一個對象person1,需要和person2判斷,判斷person1是否比person2更年老或年輕,實際上,這個方法同樣也是返回一個int,但是我們使用的是另外的接口(IComparer)的Compare來寫,所以可和下面的代碼說明person1更年老還是更年輕。
1 if(personComparer.Compare(person1,person2) == 0) 2 { 3 Console.WriteLine("same age"); 4 } 5 else if(personComparer.Compare(person1,person2) > 0 ) 6 { 7 Console.WriteLine("person 1 is older"); 8 } 9 else 10 { 11 Console.WriteLine("person1 is younger"); 12 }
在這兩種情況下,提供給方法的參數(person1、person2)是system.object類型。也就是說,可以比較任意類型的兩個對象。所以,在返回結果之前,通常需要進行某種類型比較,如果使用了錯誤的類型,還會拋出異常。實際上,我們是使用泛型接口IComparable<T>,可以省略對象轉換。
對象之間的大小比較,在開發過程中用的還是很多的,比如:string是一個可比較對象,它具有和另外一個String比較的能力,它會使用字母序進行比較。但是,有時候我們的一些邏輯需要一些特殊的比較方法。例如:WindowsExplorer 中的文件排序會認為”File10.txt" > "File2.txt"。這時候,我們就需要寫一個特殊的IComparer對象實現這些特定的邏輯。
-----------------------------------------------------------------------------分割線-----------------------------------------------------------------------------
IComparable.CompareTo(Object x)的比較方式:
compareTo()的返回值是整型類型,它是先比較對應字符的大小(ASCII碼順序),如果第一個字符和另一個參數的第一個字符不等,結束比較,返回他們ASCII碼之間的差值,如果第一個字符和另一個參數的第一個字符相等,則以第二個
字符和另一個參數的第二個字符做比較,以此類推,直至比較的字符或被比較的字符有一方全比較完,這時就比較字符的長度.
舉個Java的例子說明:
String s1 = "abc";
String s2 = "abcd";
String s3 = "abcdefg";
String s4 = "1bcdfg";
String s5 = "cdfg";
System.out.println( s1.compareTo(s2) ); // -1 (前面相等,s1長度小1)
System.out.println( s1.compareTo(s3) ); // -4 (前面相等,s1長度小4)
System.out.println( s1.compareTo(s4) ); // 48 ("a"的ASCII碼是97,"1"的的ASCII碼是49,所以返回48)
System.out.println( s1.compareTo(s5) ); // -2 ("a"的ASCII碼是97,"c"的ASCII碼是99,所以返回-2)
-----------------------------------------------------------------------------分割線-----------------------------------------------------------------------------
C# 如何實現compareTo()方法
那么在什么時候使用Icomparable.CompareTo(object obj)方法呢?
如果一個類實現了Icomparable接口,就可以重寫Icomparable接口中的CompareTo(object obj)方法,假設集合中有幾個學員對象,要按學員的姓名進行排序,那么就可以重寫CompareTo方法按姓名排序,但如果又想按年齡排序了怎么辦?CompareTo方法只能重寫一次啊,這時就可以用到Icompare了。Icompare就叫做比較器,集合默認的Sort()排序方法有種重載的參數就是Icompare比較器對象。
像所有集合類一樣,它允許您對所有實現了IComparable接口的對象進行排序。在下一個例子中,您將修改NameCompare類以實現IComparable的泛型接口:
public class NameCompare: IComparable<Student>
實現IComparable<Student>接口,NameCompare對象必須提供CompareTo()方法:
1 class NameCompare:IComparer<Student> //姓名升序 2 { 3 public int Compare(Student x, Student y) 4 { 5 return x.Name.CompareTo(y.Name); 6 } 7 } 8 9 class NameCompare1 : IComparer<Student> //姓名降序 10 { 11 public int Compare(Student x, Student y) 12 { 13 return y.Name.CompareTo(x.Name); 14 } 15 } 16 17 class AgeCompare : IComparer<Student> 18 { 19 public int Compare(Student x, Student y) 20 { 21 return x.Age.CompareTo(y.Age); 22 } 23 }
要排序的時候:
1 private void button3_Click(object sender, EventArgs e) 2 { 3 init(); 4 students.Sort(new NameCompare()); //姓名升序,Sort方法的參數就是實現了Icompare接口的類的對象 5 show(students); 6 } 7 8 private void button4_Click(object sender, EventArgs e) 9 { 10 init(); 11 students.Sort(new NameCompare1()); //姓名降序 12 show(students); 13 } 14 15 private void button5_Click(object sender, EventArgs e) 16 { 17 init(); 18 students.Sort(new AgeCompare()); 19 show(students); 20 }