восходящий / нисходящий в 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;

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

4 68

4 ответа:

вы можете легко создать свой собственный метод расширения на 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);

С точки зрения того, как это реализовано, это изменяет метод - от 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. Это действительно полезно только для числовых данных, но это дерзкий способ достижение того же результата.

Как насчет заказа desc по нужному свойству,

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

и потом делать что-то вроде

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

это обратный() слишком медленно?

в дополнение к прекрасному решению, данному @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);
    }