现在的位置: 首页 > 综合 > 正文

NET常见类系列探究——Array.Sort的方法排序本质

2012年10月12日 ⁄ 综合 ⁄ 共 5972字 ⁄ 字号 评论关闭

       不知大家是否注意到NET中有一个默认升序排序方法,位于SystemArray类中,属于静态方法。当你使用整数或者字符串数组作为参数传入时它将执行排序操作,代码如下所示:

 (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 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

 

     然后将Student的相应属性赋值,构成数组stus,(这儿代码省略);然后调用Array.Sort (stus)排序……,结果如何?

 

     很遗憾,程序崩溃无法正常运行。并且抛出了一个“System.InvalidOperationException”异常,提示说“必须至少有一个对象实现IComparable”。

         IComparable是什么接口?为什么实现它就可排序了呢?我们可以先按照提示,写一个IComparable,然后鼠标右键,点击“查看定义”,这样VS将自动查询该接口的原始定义:

 

(VB.NET):

Code

 (C#):

public interface IComparable
{
    
int CompareTo (Object obj);
}

 

再进一步查看该方法的说明,您发现:当返回值大于0,则当前实例大于obj;当返回值小于0,则当前实例小于obj;等于0则两者相等。因此它是一个类比较排序接口。

    如果我们将上面的类继承了该接口,那么就可以进行排序了,代码如下:

 

(VB.NET):

Code

(C#):

Code

        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)时候,ArraySort方法内部完成了如下操作:

 

(VB.NET):

Code

(C#):

Code

 

这个代码之所以不使用明码,而用伪代码取而代之,是因为排序循环依赖具体实现的方法(选择、冒泡、插入……)。这里只是给出一个思想,诉您CompareTo作用是用于比较两个结构或类(复合类型)的“大小”(根据某个“可比性”)。所以你如果没有实现IComparable接口,类本身不会具有“CompareTo”方法,自然运行要报错了。当然,您即使不继承此类,直接写一个CompareTo在类里头也可以,因为接口只要找寻到“同名函数、同类型返回以及相同的参数列表”的函数就可以了

       进一步扩充——可能有读者要问:那么如果我要实现两种排序方法:“有时按姓名升序,有时按成绩降序”怎么办?读者可以查找该方法的重载函数,定义如下:

 

Array.Sort (T[] objs, IComparer<T> comparer)

 

IComparer<T>接口定义如下:

 

 

(VB.NET):

 

Code

(C#):

 

 Code

 

同样地,当返回值大于0obj1>obj2;返回值等于0obj1=obj2;返回值小于0obj1<obj2

 

我们可以重新写两个“姓名排序”和“成绩排序”的类,分别继承IComparer<T>接口,代码如下:

(VB.NET):

 

Code

(C#):

 

Code

 

     调用时,只要按照“Array.Sort(排序的数组, 继承IComparer<T>的类)”即可。如上面要对姓名按照升序排列,只要Array.Sort (stus, new SortByName()) 就可以了。

     这个重载方法内部实现如下:

 

 

(VB.NET):

 

Code

(C#):

 

Code

抱歉!评论已关闭.