建立可对任意属性排序的对象集合

 

现在逻辑多层的设计方式已经深入人心。一般业务层会返回一个对象集合供其它层来使用,这个对象集合有的用数组来装载、有的用DataTable来装载、有的用类型化的DataSet来装载、有的用泛型List对象来装载。在使用泛型List对象来装载的方法时会遇到当这个集合绑定到GridView等可排序控件后并不能很好的实现排序功能。默认的List<T>支持排序方法Sort(Icomparer<T>) Sort(Comparison<T>),这并不能帮助我们排序任何类型的属性,要知道一般一个类的属性类型是非常的多。

在这篇文章中我们以一个非常常见的User类为例子,来介绍如何利用SortableList<T>来实现排序任意类型属性值的方法。User类包括IDint),UserNamestring),JoinDateDateTime),UserType(自定义枚举类型),isActivebool)。我们用Sortable<T>来装载User对象的集合,SortableList<T>继承自List<T>, Sortable<T>中的Sort方法提供两个参数要排序的属性名称和排序的方向(升序或降序)。

User类

public   enum  UserTypeEnum
{
    Manager,
    ProjectLead,
    TeamLead,
    SeniorSoftwareEngineer,
    SoftwareEngineer
}
///   <summary>
///  User类
///   </summary>
public   class  User
{
    
public  User( int  id,  string  userName,DateTime joinDate, UserTypeEnum userType,  bool  isActive)
    {
        
this .id  =  id;
        
this .userName  =  userName;
        
this .joinDate  =  joinDate;
        
this .userType  =  userType;
        
this .isActive  =  isActive;
    }

    
private   int  id;

    
public   int  Id
    {
        
get  {  return  id; }
        
set  { id  =  value; }
    }
    
private   string  userName  =   string .Empty ;

    
public   string  UserName
    {
        
get  {  return  userName; }
        
set  { userName  =  value; }
    }
    
private  DateTime joinDate  =  DateTime.MinValue;

    
public  DateTime JoinDate
    {
        
get  {  return  joinDate; }
        
set  { joinDate  =  value; }
    }
    
private  UserTypeEnum userType  =  UserTypeEnum.SoftwareEngineer;

    
public  UserTypeEnum UserType
    {
        
get  {  return  userType; }
        
set  { userType  =  value; }
    }
    
private   bool  isActive  =   false ;

    
public   bool  IsActive
    {
        
get  {  return  isActive; }
        
set  { isActive  =  value; }
    }
}

 

SortableList类

using  System;
using  System.Collections.Generic;
using  System.Text;
using  System.ComponentModel;

///   <summary>
///  可排序集合类
///   </summary>
public   class  SortableList < T > : List < T >
{
    
private   string  _propertyName;
    
private   bool  _ascending;

    
///   <summary>
    
///  排序
    
///   </summary>
    
///   <param name="propertyName"> 属性名称 </param>
    
///   <param name="ascending"> 如果设置 <c> true </c>  升序 </param>
    
///  2007-2-16 23:35 KOSTECH-ACER
     public   void  Sort( string  propertyName,  bool  ascending)
    {
        
if  (_propertyName  ==  propertyName  &&  _ascending  ==  ascending)
            _ascending 
=   ! ascending;
        
else
        {
            _propertyName 
=  propertyName;
            _ascending 
=  ascending;
        }

        PropertyDescriptorCollection properties 
=  TypeDescriptor.GetProperties( typeof (T));
        PropertyDescriptor propertyDesc 
=  properties.Find(propertyName,  true );

        
//  应用排序
        PropertyComparer < T >  pc  =   new  PropertyComparer < T > (propertyDesc, (_ascending)  ?  ListSortDirection.Ascending : ListSortDirection.Descending);
        
this .Sort(pc);
    }

}

 

PropertyComparer<T>类

using  System;
using  System.ComponentModel;
using  System.Collections.Generic;
using  System.Reflection;

///   <summary>
///  属性比较类
///   </summary>
public   class  PropertyComparer < T >  : System.Collections.Generic.IComparer < T >
{

    
private  PropertyDescriptor _property;
    
private  ListSortDirection _direction;

    
public  PropertyComparer(PropertyDescriptor property, ListSortDirection direction)
    {
        _property 
=  property;
        _direction 
=  direction;
    }

    
#region  IComparer<T>

    
public   int  Compare(T xWord, T yWord)
    {
        
//  获取属性
         object  xValue  =  GetPropertyValue(xWord, _property.Name);
        
object  yValue  =  GetPropertyValue(yWord, _property.Name);

        
//  调用升序或降序方法
         if  (_direction  ==  ListSortDirection.Ascending)
        {
            
return  CompareAscending(xValue, yValue);
        }
        
else
        {
            
return  CompareDescending(xValue, yValue);
        }
    }

    
public   bool  Equals(T xWord, T yWord)
    {
        
return  xWord.Equals(yWord);
    }

    
public   int  GetHashCode(T obj)
    {
        
return  obj.GetHashCode();
    }

    
#endregion

    
///   <summary>
    
///  比较任意类型属性升序
    
///   </summary>
    
///   <param name="xValue"> X值 </param>
    
///   <param name="yValue"> Y值 </param>
    
///   <returns></returns>
    
///  2007-2-16 23:41 KOSTECH-ACER
     private   int  CompareAscending( object  xValue,  object  yValue)
    {
        
int  result;

        
//  如果值实现了IComparer接口
         if  (xValue  is  IComparable)
        {
            result 
=  ((IComparable)xValue).CompareTo(yValue);
        }
        
//  如果值没有实现IComparer接口,但是它们是相等的
         else   if  (xValue.Equals(yValue))
        {
            result 
=   0 ;
        }
        
//  值没有实现IComparer接口且它们是不相等的, 按照字符串进行比较
         else  result  =  xValue.ToString().CompareTo(yValue.ToString());

        
return  result;
    }

    
///   <summary>
    
///  比较任意类型属性降序
    
///   </summary>
    
///   <param name="xValue"> X值 </param>
    
///   <param name="yValue"> Y值 </param>
    
///   <returns></returns>
    
///  2007-2-16 23:42 KOSTECH-ACER
     private   int  CompareDescending( object  xValue,  object  yValue)
    {
        
return  CompareAscending(xValue, yValue)  *   - 1 ;
    }

    
///   <summary>
    
///  获取属性值
    
///   </summary>
    
///   <param name="value"> 对象 </param>
    
///   <param name="property"> 属性 </param>
    
///   <returns></returns>
    
///  2007-2-16 23:42 KOSTECH-ACER
     private   object  GetPropertyValue(T value,  string  property)
    {
        
//  获取属性
        PropertyInfo propertyInfo  =  value.GetType().GetProperty(property);

        
//  返回值
         return  propertyInfo.GetValue(value,  null );
    }
}

 

TypeDescriptor类的GetProperties方法将返回一个组件或是一个类型的所有属性集合,PropertyDescriptorCollectionFind方法将返回指定属性名称的PropertyDescriptor对象,其中用bool型来表示是否忽略属性名称的大小写。PropertyDescriptor是指定的属性, 如果指定的属性不存在的话将返回NULL

 

现在我们可以比较任意的属性值了。这里我们使用Rockford LhotkaMSDN中写的PropertyComaparer<T> 类。

 

PropertyComparer建立的比较逻辑是基于Rockford Lhotka的文章。 (注意:关于比较的细节超出了本文的范围, 如果需要更细致的了解,我建议你去仔细阅读 Rocky's的文章)

 

下面是在ASP.NET页面上实现的排序功能代码。

Default.aspx.cs

public   partial   class  _Default : System.Web.UI.Page 
{
    
protected   void  Page_Load( object  sender, EventArgs e)
    {
        
if  ( ! IsPostBack)
        {
            SortableList
< User >  list  =  BuildList();
            Push( list );
            UsersGridView.DataSource 
=  list;
            UsersGridView.DataBind();
        }
    }

    
///   <summary>
    
///  处理分页事件
    
///   </summary>
    
///   <param name="sender"> The source of the event. </param>
    
///   <param name="e"> The  <see cref="System.Web.UI.WebControls.GridViewPageEventArgs"/>  instance containing the event data. </param>
    
///  2007-2-16 23:31 KOSTECH-ACER
     protected   void  UsersGridView_PageIndexChanging( object  sender, GridViewPageEventArgs e)
    {
        SortableList
< User >  list  =  Cache[ " Users " as  SortableList < User > ;
        UsersGridView.PageIndex 
=  e.NewPageIndex;
        UsersGridView.DataSource 
=  list;
        UsersGridView.DataBind();
    }

    
///   <summary>
    
///  处理排序事件
    
///   </summary>
    
///   <param name="sender"> The source of the event. </param>
    
///   <param name="e"> The  <see cref="System.Web.UI.WebControls.GridViewSortEventArgs"/>  instance containing the event data. </param>
    
///  2007-2-16 23:29 KOSTECH-ACER
     protected   void  UsersGridView_Sorting( object  sender, GridViewSortEventArgs e)
    {
        SortableList
< User >  list  =  Cache[ " Users " as  SortableList < User > ;
        list.Sort(e.SortExpression, (e.SortDirection 
==  SortDirection.Ascending));
        Push( list );
        UsersGridView.DataSource 
=  list;
        UsersGridView.DataBind();
    }

    
///   <summary>
    
///  对象集合放入缓存
    
///   </summary>
    
///   <param name="list"> The list. </param>
    
///  2007-2-16 23:33 KOSTECH-ACER
     private   void  Push ( SortableList < User >  list )
    {
        
//  排序后集合放入缓存
        Cache.Insert(  " Users " , list,  null ,
                System.Web.Caching.Cache.NoAbsoluteExpiration,
                System.Web.Caching.Cache.NoSlidingExpiration,
                System.Web.Caching.CacheItemPriority.High,
                
null  );
    }

    
///   <summary>
    
///  创建User对象集合
    
///   </summary>
    
///   <returns></returns>
    
///  2007-2-16 23:29 KOSTECH-ACER
     public  SortableList < User >  BuildList()
    {
        SortableList
< User >  list  =   new  SortableList < User > ();
        list.Add(
new  User( 1 " 张三 " , DateTime.Parse( " 24/May/2006 " ), UserTypeEnum.TeamLead,  false ));
        list.Add(
new  User( 2 " 李四 " , DateTime.Parse( " 24/Jun/2006 " ), UserTypeEnum.SoftwareEngineer,  true ));
        list.Add(
new  User( 3 " 王五 " , DateTime.Parse( " 12/Apr/2006 " ), UserTypeEnum.ProjectLead,  true ));
        list.Add(
new  User( 4 " 赵六 " , DateTime.Parse( " 12/Mar/2006 " ), UserTypeEnum.TeamLead,  false ));
        list.Add(
new  User( 5 " 刘德华 " , DateTime.Parse( " 31/May/2006 " ), UserTypeEnum.SeniorSoftwareEngineer,  true ));
        list.Add(
new  User( 6 " 张学友 " , DateTime.Parse( " 30/Sep/2006 " ), UserTypeEnum.Manager,  true ));
        list.Add(
new  User( 7 " 黎明 " , DateTime.Parse( " 1/Jul/2006 " ), UserTypeEnum.ProjectLead,  true ));
        list.Add(
new  User( 8 " 郭富城 " , DateTime.Parse( " 22/Aug/2006 " ), UserTypeEnum.SoftwareEngineer,  true ));
        list.Add(
new  User( 9 " 姚明 " , DateTime.Parse( " 17/Jan/2006 " ), UserTypeEnum.SoftwareEngineer,  true ));
        
return  list;
    }
}

 

原文链接:http://www.codeproject.com/csharp/ASPNet_Sorting.asp

 

运行环境Windows Server 2003IE7VS 2005

 

我已经整理了全部代码有需要的请留下email地址,方便我发送。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 12
    评论
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值