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

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

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

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


当前回答

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

将函数编写为通用函数:

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”方式,但它可能会给你一个如何以通用方式实现的线索

其他回答

要在.Net 2.0上不使用LINQ的情况下执行此操作,请执行以下操作:

List<Order> objListOrder = GetOrderList();
objListOrder.Sort(
    delegate(Order p1, Order p2)
    {
        return p1.OrderDate.CompareTo(p2.OrderDate);
    }
);

如果你在.Net 3.0上,那么LukeH的答案就是你在追求什么。

要对多个财产进行排序,您仍然可以在委托中进行排序。例如:

orderList.Sort(
    delegate(Order p1, Order p2)
    {
        int compareDate = p1.Date.CompareTo(p2.Date);
        if (compareDate == 0)
        {
            return p2.OrderID.CompareTo(p1.OrderID);
        }
        return compareDate;
    }
);

这将为您提供具有降序ID的升序日期。

然而,我不建议使用委托,因为这意味着很多地方没有代码重用。您应该实现一个IComparer,并将其传递给Sort方法。请参见此处。

public class MyOrderingClass : IComparer<Order>
{
    public int Compare(Order x, Order y)
    {
        int compareDate = x.Date.CompareTo(y.Date);
        if (compareDate == 0)
        {
            return x.OrderID.CompareTo(y.OrderID);
        }
        return compareDate;
    }
}

然后,要使用这个IComparer类,只需实例化它并将其传递给Sort方法:

IComparer<Order> comparer = new MyOrderingClass();
orderList.Sort(comparer);

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

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

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

将函数编写为通用函数:

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”方式,但它可能会给你一个如何以通用方式实现的线索

我能想到的最简单的方法是使用Linq:

List<Order> SortedList = objListOrder.OrderBy(o=>o.OrderDate).ToList();

罗杰版本的改进版。

GetDynamicSortProperty的问题是只获取属性名称,但如果在GridView中使用NavigationProperties会发生什么?它将发送一个异常,因为它找到null。

例子:

“Employee.Company.Name;”将崩溃。。。因为只允许“Name”作为参数获取其值。

这是一个改进的版本,允许我们按导航财产排序。

public object GetDynamicSortProperty(object item, string propName)
    {
        try
        {                 
            string[] prop = propName.Split('.'); 

            //Use reflection to get order type                   
            int i = 0;                    
            while (i < prop.Count())
            {
                item = item.GetType().GetProperty(prop[i]).GetValue(item, null);
                i++;
            }                     

            return item;
        }
        catch (Exception ex)
        {
            throw ex;
        }


    }