在最近一个项目中,有需求要对页面中所有的gridview添加排序功能。由于gridview的数据源绑定的是一个集合类List,而不是DataTable,所以无法使用DataView排序功能。另外,不同的gridview显示的是不同的业务数据,为了重用代码只能添加一个泛型方法,使用该方法对数据类型T,按照任意给定的属性进行排序。由于是要按照某个不固定的属性对List内的对象进行排序,所以修改类型T,使之实现IComparable接口,并利用List类的Sort () 方法进行排序是无法满足需求的。但是List类还提供了另一个Sort方法,它接受一个IComparer对象作为参数,在IComparer内可以实现排序的业务逻辑。唯一需要的就是进行排序的属性了,而这个在程序的上下文是已知的。
思路已经有了,但动手写代码前,google了一下相关文章,竟然发现有一段功能类似的代码,唯一不同是该该代码的实现中方法并不是泛型的。但是强大的地方是,代码中对实现的排序支持按照多个属性排序。于是稍加修改,一段强大的支持按照多属性对List进行排序的泛型方法就出炉了。
首先是表示排序属性和排序方向的类SortClass,其中保存了排序的属性和排序的方向。
Code
/// <summary>
/// Class used to hold sort information
/// </summary>
public class SortClass
{
private string _sortProperty;
public string SortProperty
{
get { return _sortProperty; }
set { _sortProperty = value; }
}
private SortDirection _sortDirection;
public SortDirection SortDirection
{
get { return _sortDirection; }
set { _sortDirection = value; }
}
public SortClass(string sortProperty, SortDirection sortDirection)
{
_sortProperty = sortProperty;
_sortDirection = sortDirection;
}
有了SortClass后就可以开始实现IComparar接口了。下面是Comparer的代码,它实现了IComparar接口,包含实际的排序功能。从代码中可以看出,Comparer通过递归调用CheckSort方法来首先按照多个属性排序的。
Code
/// <summary>
/// Implementation of IComparer
/// </summary>
public class Comparer<T> : IComparer<T>
{
private List<SortClass> _sortClasses;
/// <summary>
/// Collection of sorting criteria
/// </summary>
public List<SortClass> SortClasses
{
get { return _sortClasses; }
}
/// <summary>
/// Default Constructor
/// </summary>
public Comparer()
{
_sortClasses = new List<SortClass>();
}
/// <summary>
/// Constructor that takes a sorting class collection as param
/// </summary>
/// <param name="sortClass">
/// Collection of sorting criteria
///</param>
public Comparer(List<SortClass> sortClass)
{
_sortClasses = sortClass;
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="sortProperty">Property to sort on</param>
/// <param name="sortDirection">Direction to sort</param>
public Comparer(string sortProperty, SortDirection sortDirection)
{
_sortClasses = new List<SortClass>();
_sortClasses.Add(new SortClass(sortProperty, sortDirection));
}
/// <summary>
/// Implementation of IComparer interface to compare to object
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
/// <returns></returns>
public int Compare(T x, T y)
{
if (SortClasses.Count == 0)
{
return 0;
}
return CheckSort(0, x, y);
}
/// <summary>
/// Recursive function to do sorting
/// </summary>
/// <param name="sortLevel">Current level sorting at</param>
/// <param name="myObject1"></param>
/// <param name="myObject2"></param>
/// <returns></returns>
private int CheckSort(int sortLevel, T myObject1, T myObject2)
{
int returnVal = 0;
if (SortClasses.Count - 1 >= sortLevel)
{
object valueOf1 = myObject1.GetType().GetProperty(SortClasses[sortLevel].SortProperty).GetValue(myObject1, null);
object valueOf2 = myObject2.GetType().GetProperty(SortClasses[sortLevel].SortProperty).GetValue(myObject2, null);
if (SortClasses[sortLevel].SortDirection == SortDirection.Ascending)
{
returnVal = ((IComparable)valueOf1).CompareTo((IComparable)valueOf2);
}
else
{
returnVal = ((IComparable)valueOf2).CompareTo((IComparable)valueOf1);
}
if (returnVal == 0)
{
returnVal = CheckSort(sortLevel + 1, myObject1, myObject2);
}
}
return returnVal;
}
}
准备工作完成后,就可以开始实现真正强大的泛型排序方法了。ListSorter提供了2个静态方法,一个用来对多个属性排序,另一个为了方便只针对一个属性进行排序的情况。
Code
public class ListSorter
{
public static List<T> SortList<T>(List<T> listToSort,
List<string> sortExpression,
List<SortDirection> sortDirection)
{
//check parameters
if (sortExpression.Count != sortDirection.Count||
sortExpression.Count==0||
sortDirection.Count==0)
{
throw new Exception("Invalid sort arguments!");
}
//get myComparer
Comparer<T> myComparer = new Comparer<T>();
for (int i = 0; i < sortExpression.Count; i++)
{
SortClass sortClass = new SortClass(sortExpression[i], sortDirection[i]);
myComparer.SortClasses.Add(sortClass);
}
listToSort.Sort(myComparer);
return listToSort;
}
public static List<T> SortList<T>(List<T> listToSort,
string sortExpression,
SortDirection sortDirection)
{
//check parameters
if (sortExpression == null || sortExpression == string.Empty ||
sortDirection == null)
{
return listToSort;
}
Comparer<T> myComparer = new Comparer<T>();
myComparer.SortClasses.Add(new SortClass(sortExpression, sortDirection));
listToSort.Sort(myComparer);
return listToSort;
}
}
有了上面的代码,只需简单几行就可以轻松实现对泛型List的排序功能了:
Code
List<Project> projectList=..
List<Project> sortedProject =
ListSorter.SortList(projectList, "Name", SortDirection.Ascending);