2017-10-18 9 views
0

Je veux créer une manière dynamique de renvoyer une liste triée par le paramètre xy. La liste peut être triée par ordre décroissant, ascendant, par identifiant, nom d'utilisateur, courrier électronique et bien d'autres choses encore.dotnet .net core 2 OrderBy/OrderByDescending avec le paramètre générique

Je reçois ce paramètre sous forme de chaîne. Ainsi par exemple sort=-username

Le moins indique que la liste est descendante. Et le paramètre de tri est nom d'utilisateur.

Je reviens donc user.OrderByDescending(o => o.Username).ToList();

Au moment, avec l'aide d'une longue construction si-bien je perçois que le tri est nécessaire. Mon espoir est que je peux remplacer le paramètre de chaîne de tri avec l'aide d'une fonction au paramètre d'objet.

pseudocode

//input for example: sort=-username 
Boolean isAscending = isAscending(sort) //return true or false 
var parameter = isSortStringInsideObject(sort) // 
if (isAscending) { 
    user.OrderBy(o => o.parameter).ToList(); 
} else { 
    user.OrderByDescending(o => o.parameter).ToList(); 
} 

Donc paramètre peut être tous les paramètres dans l'objet.

Je suis nouveau dans le noyau .net. J'espère donc que je n'ai pas formulé d'exigence utopique.

+0

réflexion pourrait être utile ici: https://stackoverflow.com/a/19276588/1462295 – BurnsBA

+2

vous pourriez utiliser la réflexion d'une certaine manière, mais pour être honnête, à moins qu'il y ait vraiment beaucoup de propriétés différentes, vous feriez mieux d'utiliser simplement une grosse déclaration de commutateur – mikelegg

+1

Vous avez peut-être déjà essayé, mais avez-vous envisagé d'inclure la bibliothèque System.Linq.Dynamic à votre projet? Cela vous permettrait de faire des tris dynamiques (basés sur des chaînes de caractères) – ullfindsmit

Répondre

2

Quelque chose comme ça devrait faire l'affaire (par réflexion):

var isAscending = GetIsAscending(sort); 
var pi = typeof(User).GetProperty(parameter); 
if (pi != null) 
    user = isAscending 
     ? user.OrderBy(a => pi.GetValue(a, null)) 
     : user.OrderByDescending(a => pi.GetValue(a, null)); 
0

Je vais essayer de le garder dactylographiée et utiliser une carte avec des chaînes à funcs afin que vous puissiez rechercher la valeur à venir et mapper .

var list = new List<Item> { new Item() { Name = "aob", Age = 11 }, new Item() {Name = "bob", Age = 10},}; 
var input = "-name"; 

var map = new Dictionary<string, Func<Item, object>>() 
{ 
    {"name", x => x.Name}, 
    {"age", x => x.Age} 
}; 

if (input.StartsWith('-')) 
{ 
    var orderby = map[input.Substring(1)]; 
    var orderedEnumerable = list.OrderByDescending(orderby); 
} 
else 
{ 
    var orderby = map[input]; 
    var orderedEnumerable = list.OrderBy(orderby); 
} 
0

Intéressant .. il peut être aussi pertinent d'utiliser l'espace de noms System.Linq.Expression pour créer dynamiquement une func passée à l'ordre ou OrderByDescending, surtout si de nombreux paramètres de tri possibles sont attendus.

E.g. après que nous avons un paramètre de chaîne

var parameter = isSortStringInsideObject(sort) 

il est possible de construire une fonction comme celui-ci (T est le type pour l'utilisateur):

Dictionary<string, PropertyInfo> properties = typeof(T).GetProperties().ToDictionary(pi => pi.Name); 
ParameterExpression parameterExpression = Expression.Parameter(typeof(T)); 
Expression expression = Expression.MakeMemberAccess(parameterExpression, properties[parameter]); 
Func<T, string> orderFunc = Expression.Lambda<Func<T, string>>(expression, parameterExpression).Compile(); 

ressemble un peu lourd :) mais il peut être efficace.