通用列表的动态排序标准

时间:2009-06-04 13:49:58

标签: c# generics sorting

这样做的目的是避免编写大量的if()语句。

这是我目前的代码:

public override List<oAccountSearchResults> SearchForAccounts(oAccountSearchCriteria searchOptions)
{
    List<oAccountSearchResults> results = Service.SearchForAccounts(searchOptions);
    results.Sort((a1, a2) => a2.AccountNumber.CompareTo(a1.AccountNumber));
    return results;
}

我想要做的是提供一个参数,告诉我要对哪个字段进行排序。然后动态更新我的排序条件,而不需要一堆if()语句,如:

public override List<oAccountSearchResults> SearchForAccounts(oAccountSearchCriteria searchOptions, string sortCriteria)
{
    List<oAccountSearchResults> results = Service.SearchForAccounts(searchOptions);
    if (sortCriteria == "AccountNumber")
    {
        results.Sort((a1, a2) => a2.AccountNumber.CompareTo(a1.AccountNumber));
    }
    else if (sortCriteria == "FirstName")
    {
        results.Sort((a1, a2) => a2.FirstName.CompareTo(a1.FirstName));
    }
    return results;
}

我希望在没有大约30个if()语句的情况下执行此操作,以获取可用的所有可排序条件。

任何和所有帮助将不胜感激。

使用解决方案进行编辑:

谢谢大家的回复。

大卫,你的接近工作,但我认为理查德的答案会有所改善。

这是我提出的最终解决方案。我使用David的框架作为示例和Richards实现:

using System;
using System.Collections.Generic;

namespace SortTest
{
    class Program
    {
        static void Main(string[] args)
        {


            var results1 = Search(oObject => oObject.Value1);

            foreach (oObject o in results1)
            {
                Console.WriteLine(o.Value1 + ", " + o.Value2);
            }
            Console.WriteLine(Environment.NewLine);
            var results2 = Search(oObject => oObject.Value2);

            foreach (oObject o in results2)
            {
                Console.WriteLine(o.Value1 + ", " + o.Value2);
            }


            Console.ReadLine();
        }

        public static List<oObject> Search<T>(Func<oObject, T> keyExtract) where T: IComparable 
        {
            var results = new List<oObject>
                                            {
                                                new oObject {Value1 = "A 1", Value2 = "B 2"},
                                                new oObject {Value1 = "B 1", Value2 = "A 2"}
                                            };

            results.Sort((a, b) => keyExtract(a).CompareTo(keyExtract(b)));
            return results;
        }
    }       
    class oObject
    {
        public string Value1 { get; set; }
        public string Value2 { get; set; }
    }
}

6 个答案:

答案 0 :(得分:3)

如果调用者可以提供表达式,它提取用于比较的值,则可以在比较函数中调用该委托:

public override List<oAccountSearchResults> SearchForAccounts<T>(
              oAccountSearchCriteria searchOptions,
              Func<oAccountSearchResults, T> keyExtract) where T : IComparable {
  List<oAccountSearchResults> results = Service.SearchForAccounts(searchOptions);

  results.Sort(a,b) => keyExtract(a).CompareTo(keyExtract(b)));
  return results;
}

答案 1 :(得分:2)

你可以这样试试。我已经为测试目的创建了一个示例对象:

您可以从此处查看原始来源,但为了便于阅读而进行了清理:

http://msdn.microsoft.com/en-us/library/bb534966.aspx

首先在IEnumerable上创建一个扩展方法:

public static class EnumerableExtension

    {

        public static IOrderedEnumerable<T> OrderBy<T>(this IEnumerable<T> items, string property, bool ascending)

        {

            var myObject = Expression.Parameter(typeof (T), "MyObject");



            var myEnumeratedObject = Expression.Parameter(typeof (IEnumerable<T>), "MyEnumeratedObject");



            var myProperty = Expression.Property(myObject, property);



            var myLambda = Expression.Lambda(myProperty, myObject);



            var myMethod = Expression.Call(typeof (Enumerable), ascending ? "OrderBy" : "OrderByDescending",

                                           new[] {typeof (T), myLambda.Body.Type}, myEnumeratedObject, myLambda);



            var mySortedLambda =

                Expression.Lambda<Func<IEnumerable<T>, IOrderedEnumerable<T>>>(myMethod, myEnumeratedObject).Compile();



            return mySortedLambda(items);

        }

    }

这是我们的测试对象:

class oObject

{

    public string Value1 { get; set; }

    public string Value2 { get; set; }



}

然后在你的程序中你可以这样做:

static void Main(string[] args)

        {

            var results = new List<oObject>

                                            {

                                                new oObject {Value1 = "A", Value2 = "B"},

                                                new oObject {Value1 = "B", Value2 = "A"}

                                            };



            IEnumerable<oObject> query = results.OrderBy("Value2", false);

            foreach (oObject o in query)

            {

                Console.WriteLine(o.Value1 + ", " + o.Value2);

            }

            Console.WriteLine(Environment.NewLine);

            IEnumerable<oObject> query2 = results.OrderBy("Value1", false);

            foreach (oObject o in query2)

            {

                Console.WriteLine(o.Value1 + ", " + o.Value2);

            }

            Console.ReadLine();

        }

您的结果将是:

查询1:

A,B

B,A

查询2:

B,A

A,B

答案 2 :(得分:1)

怎么样:

public override List<oAccountSearchResults> SearchForAccounts(oAccountSearchCriteria searchOptions, Comparsion<oAccountSearchResults> sortCriteria)
{
    List<oAccountSearchResults> results = Service.SearchForAccounts(searchOptions);

    results.Sort(sortCriteria);

    return results;
}

然后你就像使用它一样:

SearchForAccounts(searchOptionsObject, (x,y) => x.Property.CompareTo(y.Property));

答案 3 :(得分:1)

使用StringComparer<oAccountSearchResults>的地图,这样您就可以从字符串中找出代码术语中排序条件的含义。然后,您可以正常方式拨打Sort

private static readonly Dictionary<String,Comparer<oAccountSearchResults>>
    SortOrders = new Dictionary<String,Comparer<oAccountSearchResults>>
{
    { "AccountNumber", (a1, a2) => a2.AccountNumber.CompareTo(a1.AccountNumber) },
    { "FirstName", (a1, a2) => a2.FirstName.CompareTo(a1.FirstName) }
    // etc
};

public override List<oAccountSearchResults> SearchForAccounts(
    oAccountSearchCriteria searchOptions, string sortCriteria)
{
    Comparer< oAccountSearchCriteria> sortOrder;
    if (!SortOrders.TryGetValue(sortCriteria, out sortOrder))
    {
        throw new ArgumentException("Unknown sort order " + sortCriteria);
    }
    List<oAccountSearchResults> results = Service.SearchForAccounts(searchOptions);
    results.Sort(sortOrder);
    return results;
}

答案 4 :(得分:0)

您是否考虑过简单地返回一个IEnumerable并允许cosumer确定他们希望如何对其进行排序。

Ayende Rahien在这里为这种行为提出了令人信服的案例:http://ayende.com/Blog/archive/2009/04/18/the-dal-should-go-all-the-way-to-ui.aspx

答案 5 :(得分:0)

执行.Net框架开发人员所做的事情,并让调用者告诉您如何排序。

http://msdn.microsoft.com/en-us/library/bb534966.aspx