dotnet .net core 2 OrderBy / OrderByDescending with generic parameter

时间:2017-10-18 15:17:42

标签: c# .net sorting

我希望创建一种动态方式,通过参数xy返回排序列表。列表可以按降序,升序,按ID,用户名,邮件等排序。

我以字符串形式接收此参数。例如sort=-username

减号表示列表下降。而sort参数是用户名。

所以我返回user.OrderByDescending(o => o.Username).ToList();

此时借助长if-else结构,我可以检测出需要哪种排序。

我希望我可以借助函数将sort字符串参数替换为object参数。

伪代码

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

因此参数可以是对象中的每个参数。

我是.net核心新手。所以我希望我没有制定一个乌托邦式的要求。

3 个答案:

答案 0 :(得分:4)

这样的事情可以解决问题(使用反射):

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

答案 1 :(得分:0)

我尝试保持输入并使用带有字符串的地图来显示func,这样您就可以查找进入的值并将其映射。

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

答案 2 :(得分:0)

有趣..使用System.Linq.Expression命名空间动态创建传递给Order或OrderByDescending的func也是相关的,特别是如果需要许多可能的排序参数。

E.g。在我们有一个字符串参数

之后
var parameter = isSortStringInsideObject(sort)

可以构造这样的函数(T是用户的类型):

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

看起来有点沉重:)但它可能有效。