用多个排序构建表达式
我正在尝试构建一个用于排序的表达式,并且我编写了使用一个属性对我的列表进行排序的代码。
但是,我需要首先由一个房产分类,然后再由另一个房产分类,等等。
我的意思是我想构建一个表达式来实现类似这样的东西: students.OrderBy(fistExpression.Compile()).ThenBy(secondImpression.Complie()).ThenBy(thirdExpression.Compile())
。
那么如何动态地把那个ThenBy
方法?
这是我的代码:
Type studentType = typeof(Student);
ParameterExpression studentParam = Expression.Parameter(studentType, "x");
MemberInfo ageProperty = studentType.GetProperty("Age");
MemberExpression valueInNameProperty =
Expression.MakeMemberAccess(studentParam, ageProperty);
Expression<Func<Student, int>> orderByExpression =
Expression<Func<Student, int>>.Lambda<Func<Student, int>>(valueInNameProperty, studentParam);
var sortedStudents = students.OrderBy(orderByExpression.Compile());
我的解决方案
public static Func<Student, object> BuildPredicate(string propertyName)
{
Type studentType = typeof(Student);
ParameterExpression studentParam = Expression.Parameter(studentType, "x");
MemberInfo ageProperty = studentType.GetProperty(propertyName);
MemberExpression valueInNameProperty = Expression.MakeMemberAccess(studentParam, ageProperty);
UnaryExpression expression = Expression.Convert(valueInNameProperty, typeof (object));
Expression<Func<Student, object>> orderByExpression = Expression.Lambda<Func<Student, object>>(expression, studentParam);
return orderByExpression.Compile();
}
在你的表达式中将代码添加到object
。
这就是你如何创建一个ThenBy
链的方法:
var sortedStudents = students.OrderBy(BuildPredicate("Age"));
foreach (var property in typeof(Student).GetProperties().Where(x => !String.Equals(x.Name, "Age")))
{
sortedStudents = sortedStudents.ThenBy(BuildPredicate(property.Name));
}
var result = sortedStudents.ToList();
最后, Student
样本班:
public class Student
{
public int Age { get; set; }
public string Name { get; set; }
}
更新:
另一种方法是使用属性标记Student
,以便在OrderBy
和ThenBy
使用它们。 喜欢:
public class Student
{
[UseInOrderBy]
public int Age { get; set; }
[UseInOrderBy(Order = 1)]
public string Name { get; set; }
}
[AttributeUsage(AttributeTargets.Property)]
internal class UseInOrderByAttribute : Attribute
{
public int Order { get; set; }
}
这就是你可以使用UseInOrderByAttribute
构建排序链的方法:
Type studentType = typeof (Student);
var properties = studentType.GetProperties()
.Select(x => new { Property = x, OrderAttribute = x.GetCustomAttribute<UseInOrderByAttribute>() })
.Where(x => x.OrderAttribute != null)
.OrderBy(x => x.OrderAttribute.Order);
var orderByProperty = properties.FirstOrDefault(x => x.OrderAttribute.Order == 0);
if (orderByProperty == null)
throw new Exception("");
var sortedStudents = students.OrderBy(BuildPredicate(orderByProperty.Property.Name));
foreach (var property in properties.Where(x => x.Property.Name != orderByProperty.Property.Name))
{
sortedStudents = sortedStudents.ThenBy(BuildPredicate(property.Property.Name));
}
var result = sortedStudents.ToList();
修复: BuildPredicate
可以在没有dynamic
情况下写入。 BuildPredicate
示例代码已更改。
我假设你有私人财产,你想能够排序。 如果你例如有这个类:
public class Student
{
public Student (int age, string name)
{
Age = age;
Name = name;
}
private string Name { get; set; }
public int Age { get; set; }
public override string ToString ()
{
return string.Format ("[Student: Age={0}, Name={1}]", Age, Name);
}
}
您可以使用以下方法构建将同时获得公共和私有属性的表达式:
public static Func<TType, TResult> CreateExpression<TType, TResult>(string propertyName)
{
Type type = typeof(TType);
ParameterExpression parameterExpression = Expression.Parameter(type, propertyName);
MemberInfo property = type.GetProperty(propertyName, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
MemberExpression valueInProperty = Expression.MakeMemberAccess(parameterExpression, property);
return Expression.Lambda<Func<TType,TResult>>(valueInProperty, parameterExpression).Compile();
}
使用示例:
var students = new [] {
new Student(20, "Ben"),
new Student(20, "Ceasar"),
new Student(20, "Adam"),
new Student(21, "Adam"),
};
var sortedStudents = students
.OrderBy(CreateExpression<Student, string>("Name"))
.ThenBy(CreateExpression<Student, int>("Age"));
sortedStudents.ToList().ForEach(student => Console.WriteLine(student));
/*
Prints:
[Student: Age=20, Name=Adam]
[Student: Age=21, Name=Adam]
[Student: Age=20, Name=Ben]
[Student: Age=20, Name=Ceasar]
*/
链接地址: http://www.djcxy.com/p/11709.html
上一篇: build an expression with multiple sorting
下一篇: Slow UIViewController load time (slow ClientState warning)