我有一个名为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#。

顺致敬意,

其他回答

基于GenericTypeTea的比较器:我们可以通过添加排序标志来获得更多的灵活性:

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

            if (OrderIdDescending) {  
                compareOrderId = -compareOrderId;  
            }  
            return compareOrderId;  
        }  

        if (DateDescending) {  
            compareDate = -compareDate;  
        }  
        return compareDate;  
    }  

    public bool DateDescending { get; set; }  
    public bool OrderIdDescending { get; set; }  
}  

在此场景中,必须将其显式实例化为MyOrderingClass(而不是IComparer)为了设置其排序财产:

MyOrderingClass comparer = new MyOrderingClass();  
comparer.DateDescending = ...;  
comparer.OrderIdDescending = ...;  
orderList.Sort(comparer);  

如果需要对Question实体中的字符串Id进行排序使用Sort函数和委托在解析Id后对Id进行排序价值

    class Question
    {
        public List<QuestionInfo> Questions Info{ get; set; }
    
    }

    class QuestionInfo
    {
        public string Id{ get; set; }
        public string Questions{ get; set; }
    
    }

    var questionnaire = new Question();
     questionnaire.QuestionInfo.Sort((x, y) => int.Parse(x.Id, CultureInfo.CurrentCulture) - int.Parse(y.Id, CultureInfo.CurrentCulture));

在没有Linq的情况下,正如你所说:

public class Order : IComparable
{
    public DateTime OrderDate { get; set; }
    public int OrderId { get; set; }

    public int CompareTo(object obj)
    {
        Order orderToCompare = obj as Order;
        if (orderToCompare.OrderDate < OrderDate || orderToCompare.OrderId < OrderId)
        {
            return 1;
        }
        if (orderToCompare.OrderDate > OrderDate || orderToCompare.OrderId > OrderId)
        {
            return -1;
        }

        // The orders are equivalent.
        return 0;
    }
}

然后只需在订单列表中调用.sort()

要在.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);

下面是一个通用LINQ扩展方法,它不会创建列表的额外副本:

public static void Sort<T,U>(this List<T> list, Func<T, U> expression)
    where U : IComparable<U>
{
    list.Sort((x, y) => expression.Invoke(x).CompareTo(expression.Invoke(y)));
}

要使用它:

myList.Sort(x=> x.myProperty);

我最近构建了另一个接受ICompare<U>的插件,以便您可以自定义比较。当我需要进行自然字符串排序时,这很有用:

public static void Sort<T, U>(this List<T> list, Func<T, U> expression, IComparer<U> comparer)
    where U : IComparable<U>
{    
    list.Sort((x, y) => comparer.Compare(expression.Invoke(x), expression.Invoke(y)));
}