您的位置:首页 > 编程语言 > C#

对象的排序

2016-03-02 20:41 561 查看

对象的排序

 

对象的排序和对象的筛选一样很重要,在对业务对象进行排序时,不能使用ObjectDataSource作为数据源,因为它只支持对DataView,DataTable和DataSet的自动排序.但是仍然可以对GridView编写Sorting事件的处理方法,通过拼装SQL语句,使用”Order by”子句来完成排序.

 

和进行筛选的思路一样,如果我们将业务对象缓存在服务器上,第一次访问时从数据库提取数据,然后进行缓存,后继的请求只针对缓存了的业务对象进行,这样可以降低对数据库的依赖,提高效率.

 

简单排序

List<int> list = new List<int>();
list.Add(4);
list.Add(5);
list.Add(2);
list.Add(9);
list.Add(1);

list.Sort();//队列表进行排序

可以看到,我们可以通过在List<int>上使用Sort()方法,对列表中的元素进行排序.现在我们在OrderManager.cs中心添一个方法GetSortList(),改革方法用于获取列表对象,因为GetList()方法返回的记录数太多,而在本节我们仅关注排序,所以仅返回15条记录.

public static List<Order> GetSortList()
{
List<Order> list = HttpContext.Current.Cache["sortList"] as list<Order>;
if (list == null)
{
list = GetList("select top 15 OrderId,CustomerId,ShipCountry,OrderDate From Orders");
HttpContext.Current.Cache.Insert("sortList",list);
}
return list;
}

 

关于简单排序的东西我不想多说了,因为你总能找到办法来解决,下来咱们来说一下高级排序.

 

多个属性组合排序

 

1.IComparer<T>接口介绍

上面仅仅是为了列表提供了一个默认排序,实际上,我们经常要求对多个列进行排序,还会要求按照升序或是降序,我们甚至会要求对多个列的组合进行排序,比如,先对CustomerId进行升序排序,再对OrderData降序排序.此时虽然使用CompareTo(Order other)也能实现,但是要给Order对象添加额外的字段或者属性.这些.NET框架已经考虑过了,并提供了IComparer<T>接口封装了排序规则,我们可以通过实现这个接口来完成排序.

public interface IComparer<T>
{
int Compare(T x,T y);
}
IComparer<T>只需要实现一个方法,Compare()接受两个同一类型的参数,并返回int类型的结果,与IComparable<T>类似,当返回值小于0时,表示x<y;等于0时,表示x=y;大于0时,表示x>y.需要注意的是:这个接口不是要求Order对象实现它,而是要求另一个对象实现它,比如OrderComparer,而在调用Sort()方法时,将它作为参数传递进去.因为这个OrderComparer只是用于对Order对象进行排序,不能应用于其他对象,所以我们将它声明为Order的嵌套类.

 
2.实现IComparer<T>接口

打开Order.cs文件,对它进行如下修改,先添加一个枚举SortDirection,用于表示排序的方向:

//可复用的枚举,表示排序的方向
public enum SortDirection
{
Ascending=0,
Descending
}
在Order类的内部,添加一个枚举,这个枚举类型代表了可以进行排序的属性:

//嵌套枚举,仅应用于此业务对象,可排序的属性
public enum SortField
{
OrderId,
CustomerId,
OrderDate,
Country
}

我们还需要再定义一个结构Sorter,这个结构包含两个字段,一个SortDirection类型,一个SortField类型,它封装了排序的必要信息:哪个属性按照哪种方式(升序还是降序)排序.

由于这个结构依然只是针对Order对象的,所以我们还是把它定义在Order内部:

//嵌套结构,仅应用于此业务对象,排序的属性和方法
public struct Sorter
{
public SortField field;
public SortDirection direction;
public Sorter(SortField field,SortDirection direction)
{
this.field = field;
this.direction = direction;
}
public Sorter(SortField field)
{
this.field = field;
this.direction = SortDirection.Ascending;
}
}

接着,我们在Order内部定义实现IComparer<T>的类OrderComparer:

//嵌套类,仅对此业务对象进行排序
public class OrderComparer : IComparer<Order>
{ }
问题的关键是如何实现这个类:因为我们要实现对某个属性按照某种方式进行排序,那么我们至少要将这两个参数传递进去,所以OrderComparer应该包含用于排序的SortDireaction和SortField;因为我们期望可以对多个属性组合排序,所以应该维护一个他们的列表,而SortDirection和SortField已经包含在Sorter结构中了,因此只要维护一个List<Sorter>结构就可以了:

public class OrderComparer : IComparer<Order>
{
private List<Sorter> list;

//构造函数,设定排序字段列表
public OrderComparer(List<Sorter> list)
{
this.list = list;
}
}
接着考虑如何排序,先从简单入手,我们不考虑对于多个属性的排序,只对某个属性按某种方式排序,那么我们需要添加一个CompareTo()方法,他接受排序的属性,排序的方式以及排序的两个对象,最后返回int类型,用于说明这两个对象的大小(位置的先后):

public int Compare(Order x,Order y,SortField field,SortDirection direction)
{
int result = 0;//默认排序位置不变化
switch (field)
{
case SortField.OrderId:
if (direction==SortDirection.Ascending)
{
result = x.OrderId.CompareTo(y.OrderId);
}
else
{
result = y.OrderId.CompareTo(x.OrderId);
}
break;
case SortField.CustomerId:
if (direction==SortDirection.Ascending)
{
result = x.CustomerId.CompareTo(y.CustomerId);
}
else
{
result = y.CustomerId.CompareTo(x.CustomerId);
}
break;
case SortField.OrderDate:
if (direction==SortDirection.Ascending)
{
result = x.OrderDate.CompareTo(y.OrderDate);
}
else
{
result = y.OrderDate.CompareTo(y.OrderDate);
}
break;
case SortField.Country:
if (direction==SortDirection.Ascending)
{
result = x.Country.CompareTo(y.Country);
}
else
{
result = y.Country.CompareTo(x.Country);
}
break;
default:
break;
}
return result;
}

但是这个方法不会去实现IComparer<T>接口,也没有办法进行多个列的排序.在进一步深入之前,我们考虑一下如何对两个对象的多个属性(比如A,B,C)来进行排序:先对属性A进行比较,如果属性A相同,则继续比较属性B;如果属性B相同,则继续比较属性C.在这个过程中,只要有任意一个属性不相同,就可以决定两个对象的先后顺序,也就是不再进行后面属性的比较.

 

所以,我们现在实现IComparer<T>接口,编写方法如下:

public int Compare(Order x, Order y)
{
int result = 0;
foreach (Sorter item in list)
{
result = Compare(x,y,item.field,item.direction);
if (result!=0)
{
break;
}
}
return result;
}

在这个方法中,我们遍历了List<Sorter>,并且在foreach语句中调用了我们前面定义的对单个属性的比较方法:

public int Compare(Order x,Order y,SortField field,SortDirection direction)
一旦比较结果不为0,那么就跳出循环.

 

好了,OrderComparer类的实现已经完成了,我们再看一下还有哪些地方可以完善:如果以后每次调用Sort进行排序的时候,都要先创建列表,指定排序规则,构造OrderCompare对象,显然会很麻烦,所以我们可以在类中添加一组重载了的方法GetCompare()用来简化以后调用时的操作步骤(当然这属于锦上添花的事情):

  //指定排序属性和排序方式
public static OrderComparer GetComparer(SortField field, SortDirection direction)
{
List<Sorter> list = new List<Sorter>();
Sorter sorter = new Sorter();
list.Add(sorter);
return new OrderComparer(list);
}

//排序列表
public static OrderComparer GetComparer(List<Sorter>list)
{
return new OrderComparer(list);
}
好了,这样的话,现在OrderComparer类就全部创建好了,接下来就是看看咋使用.

如何使用?楼主是没搞明白,如果有高手明白,或者你有想法们欢迎留言.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  .net C#