如何为运行时排序创建表达式树?

使用Entity Framework 4,我试图基于成员名称的集合实现动态排序。 基本上,用户可以选择要排序的字段和排序顺序。 我看过表达式树的例子,不能把它拼凑起来。 以下是一些细节:

列名集合:

public List sortColumns; sortColumns = new List(); /// Example subset of video fields. The collection will vary. sortColumns.Add("Width"); sortColumns.Add("Height"); sortColumns.Add("Duration"); sortColumns.Add("Title"); 

video类定义如下:

 public class Video { public string Title { get; set; } public int Width { get; set; } public int Height { get; set; } public float Duration { get; set; } public string Filename { get; set; } public DateTime DateCreated { get; set; } . . . } public List 

我想要做的是通过sortColumns集合枚举以在运行时构建表达式树。 此外,用户可以指定升序或降序排序,表达式树应该处理。

我为VS 2008尝试了动态LINQ库,但它似乎在VS 2010中不起作用。(我可能做错了。)

底线是我需要一个表达式树来根据用户输入动态地对video集合进行排序。 任何帮助,将不胜感激。

首先,你需要@Slace在这里写的OrderBy扩展方法。 所有这些都归功于Slace的一段很棒的代码,也是解决方案中最困难的部分! 我对它进行了一些修改,以适应您的具体情况:

 public static class QueryableExtensions { public static IQueryable OrderBy(this IQueryable source, string sortProperty, ListSortDirection sortOrder) { var type = typeof(T); var property = type.GetProperty(sortProperty); var parameter = Expression.Parameter(type, "p"); var propertyAccess = Expression.MakeMemberAccess(parameter, property); var orderByExp = Expression.Lambda(propertyAccess, parameter); var typeArguments = new Type[] { type, property.PropertyType }; var methodName = sortOrder == ListSortDirection.Ascending ? "OrderBy" : "OrderByDescending"; var resultExp = Expression.Call(typeof(Queryable), methodName, typeArguments, source.Expression, Expression.Quote(orderByExp)); return source.Provider.CreateQuery(resultExp); } } 

创建一个方法来对列表进行排序。 以下方法需要注意以下几点:

  1. List转换为IQueryable因为Enumerable运算符不接受表达式树。
  2. 该方法以相反的顺序迭代排序列的列表(假设您要为列表中的第一项提供最高排序优先级)

 private void PrintVideoList(IEnumerable sortColumns, ListSortDirection sortOrder) { var videos = this.GetVideos(); var sortedVideos = videos.AsQueryable(); foreach (var sortColumn in sortColumns.Reverse()) { sortedVideos = sortedVideos.OrderBy(sortColumn, sortOrder); } // Test the results foreach (var video in sortedVideos) { Console.WriteLine(video.Title); } } 

然后,您应该能够使用这样的方法:

 // These values are entered by the user var sortColumns = new List { "Width", "Title", "Height" }; var sortOrder = ListSortDirection.Ascending; // Print the video list base on the user selection this.PrintVideoList(sortColumns, sortOrder); 

正是我需要凯文。 我注意到的是,如果你使用orderby它只需要最后的orderby选择。

我添加了这个方法(ThenBy)到我的,它似乎运作良好

 public static IQueryable ThenBy(this IQueryable source, string sortProperty, ListSortDirection sortOrder) { var type = typeof(T); var property = type.GetTypeInfo().GetDeclaredProperty(sortProperty); var parameter = Expression.Parameter(type, "p"); var propertyAccess = Expression.MakeMemberAccess(parameter, property); var orderByExp = Expression.Lambda(propertyAccess, parameter); var typeArguments = new Type[] { type, property.PropertyType }; var methodName = sortOrder == ListSortDirection.Ascending ? "ThenBy" : "ThenByDescending"; var resultExp = Expression.Call(typeof(Queryable), methodName, typeArguments, source.Expression, Expression.Quote(orderByExp)); return source.Provider.CreateQuery(resultExp); }