Критерии динамической сортировки для общего списка - PullRequest
2 голосов
/ 04 июня 2009

Цель этого - избежать написания тонны операторов 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 () для всех доступных для сортировки критериев.

Любая и вся помощь будет оценена.

РЕДАКТИРОВАТЬ С РЕШЕНИЕМ:

Спасибо всем за ваши ответы.

Дэвид, ваш подход сработал, но я думаю, что ответ Ричарда работает немного лучше.

Вот окончательное решение, которое я придумал. Я использовал структуру Дэвида для примера и реализацию Ричардса:

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 ]

3 голосов
/ 04 июня 2009

Если вызывающая сторона может предоставить выражение , которое извлекает значение, используемое для сравнения, вы можете вызвать этот делегат в функции сравнения:

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;
}
2 голосов
/ 04 июня 2009

Вы можете попробовать это так. Я создал образец объекта для тестирования:

Вы можете просмотреть исходный код отсюда, но очищенный для удобства чтения:

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:

А, В

B, A

Запрос 2:

B, A

A, B

1 голос
/ 04 июня 2009

Используйте карту от String до Comparer<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;
}
1 голос
/ 04 июня 2009

что по этому поводу:

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));
0 голосов
/ 04 июня 2009

Сделайте то, что сделали разработчики .Net framework, и пусть звонящий скажет вам, как сортировать.

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

0 голосов
/ 04 июня 2009

Рассматривали ли вы просто вернуть IEnumerable и позволить клиенту определить, как он хотел бы отсортировать его там.

Айенде Рахиен приводит убедительные аргументы в пользу такого поведения здесь: http://ayende.com/Blog/archive/2009/04/18/the-dal-should-go-all-the-way-to-ui.aspx

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...