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

    技术2022-05-11  66

    现在逻辑多层的设计方式已经深入人心。一般业务层会返回一个对象集合供其它层来使用,这个对象集合有的用数组来装载、有的用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)