По возрастанию/убыванию в LINQ - можно изменить порядок через параметр?

У меня есть метод, которому задан параметр "bool sortAscending". Теперь я хочу использовать LINQ для создания отсортированного списка в зависимости от этого параметра. Я получил следующее:

var ascendingQuery = from data in dataList
                      orderby data.Property ascending
                      select data;

var descendingQuery = from data in dataList
                      orderby data.Property descending
                      select data;

Как вы можете видеть, оба запроса отличаются только "восходящим" или. "По убыванию". Я хотел бы объединить оба запроса, но я не знаю, как это сделать. Кто-нибудь имеет ответ?

Ответ 1

Вы можете легко создать свой собственный метод расширения в IEnumerable или IQueryable:

public static IOrderedEnumerable<TSource> OrderByWithDirection<TSource,TKey>
    (this IEnumerable<TSource> source,
     Func<TSource, TKey> keySelector,
     bool descending)
{
    return descending ? source.OrderByDescending(keySelector)
                      : source.OrderBy(keySelector);
}

public static IOrderedQueryable<TSource> OrderByWithDirection<TSource,TKey>
    (this IQueryable<TSource> source,
     Expression<Func<TSource, TKey>> keySelector,
     bool descending)
{
    return descending ? source.OrderByDescending(keySelector)
                      : source.OrderBy(keySelector);
}

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

var query = dataList.OrderByWithDirection(x => x.Property, direction);

Ответ 2

В терминах того, как это реализовано, это изменяет метод - от OrderBy/ThenBy до OrderByDescending/ThenByDescending. Однако вы можете применить сортировку отдельно к основному запросу...

var qry = from .... // or just dataList.AsEnumerable()/AsQueryable()

if(sortAscending) {
    qry = qry.OrderBy(x=>x.Property);
} else {
    qry = qry.OrderByDescending(x=>x.Property);
}

Любое использование? Вы можете создать весь "заказ" динамически, но он более задействован...

Другой трюк (в основном соответствующий LINQ-to-Objects) заключается в использовании множителя -1/1. Это действительно полезно для числовых данных, но это навязчивый способ достичь того же результата.

Ответ 3

Как насчет упорядочения desc по желаемому свойству,

   blah = blah.OrderByDescending(x => x.Property);

И затем сделав что-то вроде

  if (!descending)
  {
       blah = blah.Reverse()
  }
  else
  {
      // Already sorted desc ;)
  }

Слишком медленный режим Reverse()?

Ответ 4

В дополнение к красивому решению, данному @Jon Skeet, мне также нужны были ThenBy и ThenByDescending, поэтому я добавляю его на основе его решения:

    public static IOrderedEnumerable<TSource> ThenByWithDirection<TSource, TKey>(
         this IOrderedEnumerable<TSource> source, 
         Func<TSource, TKey> keySelector,  
         bool descending)
    {
        return descending ? 
               source.ThenByDescending(keySelector) :
               source.ThenBy(keySelector);
    }