2008-12-23 9 views
66

J'ai une méthode avec le paramètre "bool sortAscending". Maintenant, je veux utiliser LINQ pour créer une liste triée en fonction de ce paramètre. J'ai alors ceci:ascendant/descendant dans LINQ - peut-on changer l'ordre par paramètre?

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

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

Comme vous pouvez le voir, les deux requêtes ne diffèrent que par "ascendant" resp. "descendant". J'aimerais fusionner les deux requêtes, mais je ne sais pas comment. Est-ce que quelqu'un a la réponse?

+0

Vous voulez avoir une requête qui peut faire les deux ascendant ou descendant selon le tri booléen Valeur en baisse? Est-ce exact. –

Répondre

100

Vous pouvez facilement créer votre propre méthode d'extension sur IEnumerable ou 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); 
} 

Oui, vous perdez la possibilité d'utiliser une expression de requête ici - mais franchement je ne pense pas que vous êtes réellement profiter de une expression de requête de toute façon dans ce cas. Les expressions de requête sont grandes pour des choses complexes, mais si vous faites seulement une seule opération, il est plus simple de mettre cette seule opération:

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

Merci de corriger ma stupidité Marc :) (C'est le problème de poster juste avant d'aller déjeuner ...) –

+3

Eh bien, vous donnez si peu d'opportunités ;-p –

+7

Cet article a été répondu et édité par deux célébrités de SO.com –

39

Pour ce qui est de la façon dont cela est implémenté, cela modifie la méthode - de OrderBy/ThenBy à OrderByDescending/ThenByDescending. Cependant, vous pouvez appliquer le tri séparément à la requête principale ...

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

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

Toute utilisation? Vous pouvez créer l'ensemble de la "commande" dynamiquement, mais il est plus impliqué ...

Une autre astuce (principalement appropriée à LINQ-to-Objects) est d'utiliser un multiplicateur, de -1/1. Ceci n'est vraiment utile que pour les données numériques, mais c'est une manière effrontée d'atteindre le même résultat.

+0

J'étais sur le point d'écrire exactement la même chose que mon VS gelé :( –

+1

L'utilisation d'un multiplicateur échoue également pour une valeur de retour de int.MinValue –

+0

pourquoi utilisez-vous la méthode orderBy au lieu d'utiliser le mot-clé orderby dans un linq -query? – Joshit

5

Qu'en est-commande desc par la propriété désirée,

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

Et puis faire quelque chose comme

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

Est-il trop lent() trop lent?

0

En plus de la belle solution donnée par Skeet @ Jon, j'ai aussi besoin ThenBy et ThenByDescending, donc je l'ajouter en fonction de sa solution:

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); 
    } 
Questions connexes