翻译 建立可对任意属性排序的对象集合收藏

新一篇: 用C#编写ActiveX控件 | 旧一篇: 生疏了CSDN的BLOG

 

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

 

发表于 @ 2007年02月17日 10:17:00|评论(loading...)|编辑

新一篇: 用C#编写ActiveX控件 | 旧一篇: 生疏了CSDN的BLOG

评论

#babyQ 发表于2007-03-07 15:53:10  IP: 61.155.29.*
利用SerialPort类实现收发短信(C# 2.0)
想要份这篇文章的代码,那文章留言的太多了,怕你看不见,所以在这里留了,请见凉
musz@163.com
#longhorn008 发表于2007-03-16 21:33:02  IP: 125.118.66.*
我也要份,3Q
voidarea@gmail.com
#icbcom 发表于2007-09-14 16:59:33  IP: 219.130.17.*
我也要 一份 “SerialPort类实现收发短信”

上面的也要,
呵呵,

dnavip@qq.com

#qshzf 发表于2007-10-27 09:33:46  IP: 218.92.27.*
楼主 发一份给我吧,谢谢:)
#qshzf 发表于2007-10-27 09:35:11  IP: 218.92.27.*
arcc33@163.com
#xewnwsl2001 发表于2007-11-23 17:08:27  IP: 202.115.27.*
wanshulong@163.com
谢谢!
#ybb1981 发表于2007-12-02 22:35:30  IP: 121.13.177.*
guowenwu1981815@163.com
#gukai520 发表于2007-12-12 16:49:58  IP: 125.33.197.*
guvkai@gmail.com
找了好久了终于在这里看到了
大哥麻烦你了
#OliveChinese 发表于2008-01-21 22:09:10  IP: 218.5.2.*
我也要一份..刚从JAVA转到C#..急需啊..
3Q ...楼主
#OliveChinese 发表于2008-01-21 22:09:57  IP: 218.5.2.*
我也要一份..刚从JAVA转到C#..急需啊..
刚忘了留邮箱..我的:zhangzhongtao51f@163.com
3Q ...楼主
#lanwilliam 发表于2008-05-04 15:24:40  IP: 218.57.138.*
wangwenbin850411@163.com
谢了
发表评论  


当前用户设置只有注册用户才能发表评论。如果你没有登录,请点击登录
Csdn Blog version 3.1a
Copyright © veryhappy(wx.net)