我有一个名为Order的类,它具有OrderId、OrderDate、Quantity和Total等财产。我有这个订单类的列表:

List<Order> objListOrder = new List<Order>();
GetOrderList(objListOrder); // fill list of orders

我想根据Order对象的一个属性对列表进行排序;例如通过订单日期或订单id。

如何在C#中执行此操作?


当前回答

我为List<T>制作了这个扩展方法。

扩展方法将您希望排序的属性作为解析字符串,然后使用List<T>的OrderBy方法。然后,它将原始列表的每个索引设置为有序列表的相同索引。

public static class ListExtensions {
    public static void SortBy<T>(this List<T> list, string property, bool reverse = false) {
        List<T> ordered = list.OrderBy(obj => obj.GetType().GetProperty(property).GetValue(obj, null)).ToList();
            
        for (int i = 0; i < list.Count; i++)
            list[i] = reverse ? ordered[list.Count - 1 - i] : ordered[i];
    }
}

如果列表中的对象具有属性Name,则按如下方式对列表testList进行排序:

//For normal sorting order
testList.SortBy("Name");
//For reverse sorting order
testList.SortBy("Name", true);

我建议您将SortBy的名称更改为Prefix_SortBy。若要防止导入其他库时可能发生冲突。

我知道这种方法适用于字母和数字排序。其分选能力可能有限,但操作非常简单。

如果有一些重大的缺陷或问题,请告诉我,我已经编写了大约3个月的C#。

顺致敬意,

其他回答

使用LINQ

objListOrder = GetOrderList()
                   .OrderBy(o => o.OrderDate)
                   .ToList();

objListOrder = GetOrderList()
                   .OrderBy(o => o.OrderId)
                   .ToList();

您可以对财产选择做一些更通用的操作,但也可以对您选择的类型进行特定操作,例如“订单”:

将函数编写为通用函数:

public List<Order> GetOrderList<T>(IEnumerable<Order> orders, Func<Order, T> propertySelector)
        {
            return (from order in orders
                    orderby propertySelector(order)
                    select order).ToList();
        } 

然后这样使用:

var ordersOrderedByDate = GetOrderList(orders, x => x.OrderDate);

您可以更加通用,并为您想要订购的产品定义一个开放类型:

public List<T> OrderBy<T,P>(IEnumerable<T> collection, Func<T,P> propertySelector)
        {
            return (from item in collection
                    orderby propertySelector(item)
                    select item).ToList();
        } 

并以相同的方式使用:

var ordersOrderedByDate = OrderBy(orders, x => x.OrderDate);

这是一种愚蠢而不必要的复杂LINQ风格的“OrderBy”方式,但它可能会给你一个如何以通用方式实现的线索

以上答案对我来说都不够通用,所以我做了一个:

var someUserInputStringValue = "propertyNameOfObject i.e. 'Quantity' or 'Date'";
var SortedData = DataToBeSorted
                   .OrderBy(m => m.GetType()
                                  .GetProperties()
                                  .First(n => 
                                      n.Name == someUserInputStringValue)
                   .GetValue(m, null))
                 .ToList();

不过,要小心处理海量数据集。这是一个简单的代码,但如果集合是巨大的,并且集合的对象类型包含大量字段,则可能会给您带来麻烦。运行时间为NxM,其中:

N=集合中的元素数

M=对象中的财产数量

从性能的角度来看,最好使用排序列表,以便在将数据添加到结果中时对其进行排序。其他方法至少需要对数据进行一次额外的迭代,并且大多数方法都会创建数据的副本,这样不仅会影响性能,还会影响内存使用。数百个元素可能不会有问题,但数千个元素可能会有问题,特别是在许多并发请求可能同时进行排序的服务中。查看System.Collections.Generic命名空间,然后选择一个带有排序的类,而不是List。

尽可能避免使用反射的通用实现,这也会导致性能问题。

var obj = db.Items.Where...

var orderBYItemId = obj.OrderByDescending(c => Convert.ToInt32(c.ID));