简体   繁体   中英

dotnet .net core 2 OrderBy/OrderByDescending with generic parameter

I want create a dynamic way to return a sorted list by parameter xy. The list can be sorted descending, ascending, by id, username, mail and a lot of more.

I receive this parameter as string. So for example sort=-username

The minus says that the list descending. And the sort parameter is username.

So I return user.OrderByDescending(o => o.Username).ToList();

At the moment with help of a long if-else construct I detect which sorting is needed.

My hope is that I can replace the sort string parameter with help of a function to the object parameter.

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();
}

So parameter can be every parameter in object.

I'm new in .net core. So I hope I doesn't formulated an utopian requirement.

Something like this should do the trick (using reflection):

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));

Interesting.. it may be also relevant to use System.Linq.Expression namespace to dynamically create a func passed to Order or OrderByDescending, especially if many possible sort parameters are expected.

Eg after we have a string parameter

var parameter = isSortStringInsideObject(sort)

it is possible to construct a function like this (T is the type for the user):

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();

Looks a little bit heavy :) but it may be effective.

I'd try to keep it typed and use a map with strings to funcs so you can lookup the value coming in and map it.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM