不知大家是否注意到NET中有一个默认升序排序方法,位于System的Array类中,属于静态方法。当你使用整数或者字符串数组作为参数传入时它将执行排序操作,代码如下所示:
(VB.NET):
Dim g()as Integer=New Integer(){1,2,4,5,3}
Array.Sort(g)
(C#):
int[]g={1,2,4,5,3};
Array.Sort(g); //结果:1,2,3,4,5
但是你是否考虑这样一个问题——构成数组的类型不是单纯的一个“基本类型”,而是一个复合类型(比如结构或类),假如有一个Student类,定义代码如下:
(VB.NET):
Code
Public Class Student
Private stuname As string=Nothing
Private score As double =0.0
Public Property StuName()As string
Get
return stuname
End Get
Set(Value as String)
stuname=Value
End Set
End Property
Public Property Score()As dobule
Get
return score
End Get
Set(Value as double)
score=Value
End Set
End Property
End Class
(C#):
Code
public class Student
{
private string stuname=null;
private double score=0.0;
public string StuName
{
get
{
return stuname;
}
set
{
stuname=value;
}
}
public string Score
{
get
{
return score;
}
set
{
score=value;
}
}
}
然后将Student的相应属性赋值,构成数组stus,(这儿代码省略);然后调用Array.Sort (stus)排序……,结果如何?
很遗憾,程序崩溃无法正常运行。并且抛出了一个“System.InvalidOperationException”异常,提示说“必须至少有一个对象实现IComparable”。
IComparable是什么接口?为什么实现它就可排序了呢?我们可以先按照提示,写一个IComparable,然后鼠标右键,点击“查看定义”,这样VS将自动查询该接口的原始定义:
(VB.NET):
Code
Public Interface IComparable
Function CompareTo (obj As Object) As Integer
End Interface
(C#):
public interface IComparable
{
int CompareTo (Object obj);
}
再进一步查看该方法的说明,您发现:当返回值大于0,则当前实例大于obj;当返回值小于0,则当前实例小于obj;等于0则两者相等。因此它是一个类比较排序接口。
如果我们将上面的类继承了该接口,那么就可以进行排序了,代码如下:
(VB.NET):
Code
Public Class Student Implements IComparable
Private stuname As string=Nothing
Private score As double =0.0
Public Property StuName()As string
Get
return stuname
End Get
Set(Value as String)
stuname=Value
End Set
End Property
Public Property Score()As dobule
Get
return score
End Get
Set(Value as double)
score=Value
End Set
End Property
Public Function CompareTo (obj As Object) As Integer
Return (score-CType(obj,Student).score)
End Function
End Class
(C#):
Code
public class Student : IComparable
{
private string stuname=null;
private double score=0.0;
public string StuName
{
get
{
return stuname;
}
set
{
stuname=value;
}
}
public string Score
{
get
{
return score;
}
set
{
score=value;
}
}
public int CompareTo (Object obj)
{
return score-((Student)obj).score;
}
}
此时您再使用Array.Sort(stus)方法就不会出现异常,而是按照分数进行排序了。
为什么会产生这样一种情况呢?实际上,当您使用Array.Sort(stus)时候,Array的Sort方法内部完成了如下操作:
(VB.NET):
Code
Public Sub Sort(Of T)(stus As T)
For(排序外循环)
For(排序内循环)
if (stus[i].CompareTo(stus[i+1])>0) '第i个数比第i+1个数大
两个数字相互交换
Next
Next
End Sub
(C#):
Code
public void Sort<T> (T[] stus)
for (排序外循环)
{
for (排序内循环)
{
if (stus[i].CompareTo(stus[i+1])>0) //第i个数比第i+1个数大
两个数字相互交换;
}
}
这个代码之所以不使用明码,而用伪代码取而代之,是因为排序循环依赖具体实现的方法(选择、冒泡、插入……)。这里只是给出一个思想,告诉您CompareTo的作用是用于比较两个结构或类(复合类型)的“大小”(根据某个“可比性”)。所以你如果没有实现IComparable接口,类本身不会具有“CompareTo”方法,自然运行要报错了。当然,您即使不继承此类,直接写一个CompareTo在类里头也可以,因为接口只要找寻到“同名函数、同类型返回以及相同的参数列表”的函数就可以了。
进一步扩充——可能有读者要问:那么如果我要实现两种排序方法:“有时按姓名升序,有时按成绩降序”怎么办?读者可以查找该方法的重载函数,定义如下:
Array.Sort (T[] objs, IComparer<T> comparer)
其IComparer<T>接口定义如下:
(VB.NET):
Code
Public Interface IComparer(Of T)
Function CompareTo(obj1 As T,obj2 As T) As Integer
End Interface
(C#):
Code
public interface IComparer<T>
{
int CompareTo (T obj1, T obj2);
}
同样地,当返回值大于0,obj1>obj2;返回值等于0,obj1=obj2;返回值小于0,obj1<obj2;
我们可以重新写两个“姓名排序”和“成绩排序”的类,分别继承IComparer<T>接口,代码如下:
(VB.NET):
Code
Public Class SortByName Implements IComparer(Of Student)
Public Function CompareTo (obj1 As Student,obj2 As Student)As Integer
Return obj1.StuName.CompareTo(obj2.StuName) '字符串内置具有CompareTo方法比大小,作用同IComparable的那个CompareTo。
End Function
End Class
Public Class SortByScore Implements IComparer(Of Student)
Public Function CompareTo (obj1 As Student,obj2 As Student)As Integer
Return obj1.Score-obj2.Score
End Function
End Class
(C#):
Code
public class SortByName : IComparer<Student>
{
public int CompareTo (Student obj1, Student obj2)
{
return obj1.StuName.CompareTo(obj2.StuName); //字符串内置具有CompareTo方法比大小,作用同IComparable的那个CompareTo。
}
}
public class SortByScore : IComparer<Student>
{
public int CompareTo (Student obj1, Student obj2)
{
return obj1.Score-obj2.Score;
}
}
调用时,只要按照“Array.Sort(排序的数组, 继承IComparer<T>的类)”即可。如上面要对姓名按照升序排列,只要Array.Sort (stus, new SortByName()) 就可以了。
这个重载方法内部实现如下:
(VB.NET):
Code
Public Sub Sort(Of T)(stus As T(), IComparer(Of T) comparer)
For (排序外循环)
For (排序内循环)
If (comparer.CompareTo(stus(i),stus(i+1))>0) '第i个数比第i+1个数大
两个数字相互交换;
Next
Next
End Sub
(C#):
Code
public void Sort<T> (T[] stus, IComparer<T> comparer)
{
for (排序外循环)
{
for (排序内循环)
{
if (comparer.CompareTo (stus[i],stus[i+1])>0) //第i个数比第i+1个数大
两个数字相互交换;
}
}
}