我有一个名为 Order
的类,它具有 OrderId
, OrderDate
, Quantity
和 Total
等属性 . 我有一个这个 Order
类的列表:
List<Order> objListOrder = new List<Order>();
GetOrderList(objListOrder); // fill list of orders
现在我想基于 Order
对象的一个属性对列表进行排序,例如我需要按订单日期或订单ID对其进行排序 .
我怎样才能在C#中做到这一点?
19 回答
您可以对属性选择做一些更通用的事情,但在您的案例“订单”中,您可以选择具体的类型:
将您的函数编写为通用函数:
然后像这样使用它:
您可以更通用,并为要订购的内容定义开放类型:
并以相同的方式使用它:
这是一种做出LINQ风格'OrderBy'的愚蠢不必要的复杂方式,但它可能会给你一个如何以通用方式实现它的线索
利用LiNQ OrderBy
我能想到的最简单的方法是使用Linq:
//用于gridview的完全通用排序
从性能的角度来看,最好是使用排序列表,以便在将数据添加到结果时对数据进行排序 . 其他方法至少需要对数据进行一次额外迭代,并且大多数创建数据副本,因此不仅性能而且内存使用也会受到影响 . 可能不是几百个元素的问题,但会有数千个,特别是在许多并发请求可能同时进行排序的服务中 . 查看System.Collections.Generic命名空间并选择一个带有排序而不是List的类 .
并且尽可能避免使用反射的通用实现,这也可能导致性能问题 .
A Classical Object Oriented Solution
首先,我必须接受LINQ的精彩内容......现在我们已经把它排除在外了
JimmyHoffa答案的一个变种 . 使用泛型,
CompareTo
参数变为类型安全 .当然,此默认可排序性是可重用的 . 也就是说,每个客户端都不必冗余地重写排序逻辑 . 交换“1”和“-1”(或逻辑运算符,您的选择)会反转排序顺序 .
使用LINQ
任何使用可空类型的人,
Value
都需要使用CompareTo
.objListOrder.Sort((x, y) => x.YourNullableType.Value.CompareTo(y.YourNullableType.Value));
这是一个通用的LINQ扩展方法,它不会创建列表的额外副本:
要使用它:
我最近构建了另外一个接受
ICompare<U>
的,以便您可以自定义比较 . 当我需要进行自然字符串排序时,这会派上用场:请让@LukeH用一些示例代码完成答案,因为我测试了它,我相信它可能对某些人有用:
订购列表最简单的方法是使用
OrderBy
如果您想按照SQL Query之类的多个列进行排序 .
为此,您可以使用
ThenBy
,如下所示 .Roger版本的改进 .
GetDynamicSortProperty的问题是只获取属性名称但是如果在GridView中我们使用NavigationProperties会发生什么?它会发送一个异常,因为它找到了null .
例:
“Employee.Company.Name;”将崩溃...因为只允许“Name”作为参数来获取其值 .
这是一个改进版本,允许我们按导航属性进行排序 .
基于 GenericTypeTea 的Comparer:
我们可以通过添加排序标志获得更多灵活性:
在这种情况下,您必须明确地将其实例化为 MyOrderingClass (而不是 IComparer )
为了设置其排序属性:
上面的答案对我来说都不够通用,所以我做了这个:
但是要注意大量的数据集 . 它很简单,但是如果集合很大并且集合的对象类型有很多字段,那么可能会让你遇到麻烦 . 运行时间是NxM,其中:
N =集合中的元素数量
M =对象内的属性数
如果需要就地排序列表,则可以使用Sort方法,传递Comparison<T>委托:
如果您更喜欢创建一个新的排序序列而不是就地排序,那么您可以使用LINQ的OrderBy方法,如其他答案中所述 .
要在.Net2.0上没有LINQ的情况下执行此操作:
如果你're on .Net3.0, then LukeH' s answer就是你所追求的 .
要对多个属性进行排序,您仍然可以在委托中执行此操作 . 例如:
这将为您提供 ascending 日期 descending orderIds .
但是,我不建议坚持代表,因为这意味着很多地方没有代码重用 . 你应该实现
IComparer
并将其传递给你的Sort
方法 . 见here .然后使用这个IComparer类,只需实例化它并将其传递给Sort方法:
没有这样做Linq如你所说:
然后在您的订单列表中调用.sort()