我正在尝试构建一个用于排序的表达式,并且我编写了使用一个属性对列表进行排序的代码.
但我需要首先将其分类为一个属性,其次是另一个属性,依此类推.
我的意思是我想构建一个表达式来实现类似的东西: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(); }
这就是你如何创建一个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();
最后,学生样本班:
public class Student { public int Age { get; set; } public string Name { get; set; } }
更新:
另一种方法是使用属性来标记学生的属性,以便在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可以在没有动态的情况下写入. BuildPredicate示例代码已更改.