如何dynamic指定Linq OrderBy参数?

如何使用我作为参数的值来指定传递给orderby的参数?

例如:

 List<Student> existingStudends = new List<Student>{ new Student {...}, new Student {...}} 

目前的实施:

 List<Student> orderbyAddress = existingStudends.OrderBy(c => c.Address).ToList(); 

而不是c.Address ,我怎样才能把它作为一个参数?

  string param = "City"; List<Student> orderbyAddress = existingStudends.OrderByDescending(c => param).ToList(); 

这是使用reflection的可能性…

 var param = "Address"; var propertyInfo = typeof(Student).GetProperty(param); var orderByAddress = items.OrderBy(x => propertyInfo.GetValue(x, null)); 

您可以使用一点reflection来构buildexpression式树,如下所示(这是一个扩展方法):

 public static IQueryable<TEntity> OrderBy<TEntity>(this IQueryable<TEntity> source, string orderByProperty, bool desc) { string command = desc ? "OrderByDescending" : "OrderBy"; var type = typeof(TEntity); var property = type.GetProperty(orderByProperty); var parameter = Expression.Parameter(type, "p"); var propertyAccess = Expression.MakeMemberAccess(parameter, property); var orderByExpression = Expression.Lambda(propertyAccess, parameter); var resultExpression = Expression.Call(typeof(Queryable), command, new Type[] { type, property.PropertyType }, source.Expression, Expression.Quote(orderByExpression)); return source.Provider.CreateQuery<TEntity>(resultExpression); } 

orderByProperty是你想要命令的属性名称,如果传递true作为desc参数,将按降序排列; 否则,将按升序sorting。

现在你应该可以做existingStudents.OrderBy("City",true);existingStudents.OrderBy("City",false);

  private Func<T, object> GetOrderByExpression<T>(string sortColumn) { Func<T, object> orderByExpr = null; if (!String.IsNullOrEmpty(sortColumn)) { Type sponsorResultType = typeof(T); if (sponsorResultType.GetProperties().Any(prop => prop.Name == sortColumn)) { System.Reflection.PropertyInfo pinfo = sponsorResultType.GetProperty(sortColumn); orderByExpr = (data => pinfo.GetValue(data, null)); } } return orderByExpr; } public List<T> OrderByDir<T>(IEnumerable<T> source, string dir, Func<T, object> OrderByColumn) { return dir.ToUpper() == "ASC" ? source.OrderBy(OrderByColumn).ToList() : source.OrderByDescending(OrderByColumn).ToList();`` } // Call the code like below var orderByExpression= GetOrderByExpression<SearchResultsType>(sort); var data = OrderByDir<SponsorSearchResults>(resultRecords, SortDirectionString, orderByExpression); 

1)安装System.Linq.Dynamic

2)添加下面的代码

 public static class OrderUtils { public static string ToStringForOrdering<T, TKey>(this Expression<Func<T, TKey>> expression, bool isDesc = false) { var str = expression.Body.ToString(); var param = expression.Parameters.First().Name; str = str.Replace("Convert(", "(").Replace(param + ".", ""); return str + (isDesc ? " descending" : ""); } } 

3)编写您的开关selectLambdafunction

 public static class SortHelper { public static Expression<Func<UserApp, object>> UserApp(string orderProperty) { orderProperty = orderProperty?.ToLowerInvariant(); switch (orderProperty) { case "firstname": return x => x.PersonalInfo.FirstName; case "lastname": return x => x.PersonalInfo.LastName; case "fullname": return x => x.PersonalInfo.FirstName + x.PersonalInfo.LastName; case "email": return x => x.Email; } } } 

4)使用你的助手

 Dbset.OrderBy(SortHelper.UserApp("firstname").ToStringForOrdering()) 

5)你可以使用它与pagging( PagedList )

 public virtual IPagedList<T> GetPage<TOrder>(Page page, Expression<Func<T, bool>> where, Expression<Func<T, TOrder>> order, bool isDesc = false, params Expression<Func<T, object>>[] includes) { var orderedQueryable = Dbset.OrderBy(order.ToStringForOrdering(isDesc)); var query = orderedQueryable.Where(where).GetPage(page); query = AppendIncludes(query, includes); var results = query.ToList(); var total = Dbset.Count(where); return new StaticPagedList<T>(results, page.PageNumber, page.PageSize, total); } 

说明

System.Linq.Dynamic允许我们在OrderBy方法中设置string值。 但是在这个扩展中,string将被parsing为Lambda。 所以我认为这将工作,如果我们将parsingLambdastring,并将其提供给OrderBy方法。 它的工作原理!

这是我想出来处理一个有条件的降序。 您可以将其与其他dynamic生成keySelector func的方法结合使用。

  public static IOrderedQueryable<TSource> OrderBy<TSource, TKey>(this IQueryable<TSource> source, System.Linq.Expressions.Expression<Func<TSource, TKey>> keySelector, System.ComponentModel.ListSortDirection sortOrder ) { if (sortOrder == System.ComponentModel.ListSortDirection.Ascending) return source.OrderBy(keySelector); else return source.OrderByDescending(keySelector); } 

用法:

 //imagine this is some parameter var direction = System.ComponentModel.ListSortDirection.Ascending; query = query.OrderBy(ec => ec.MyColumnName, direction); 

注意这允许你将这个.OrderBy扩展与一个新的参数链接到任何IQueryable上。

 // perhaps passed in as a request of user to change sort order // var direction = System.ComponentModel.ListSortDirection.Ascending; query = context.Orders .Where(o => o.Status == OrderStatus.Paid) .OrderBy(ec => ec.OrderPaidUtc, direction); 

这不会让你传递一个string ,就像你在问题中所要求的那样,但它可能仍然适用于你。

OrderByDescending方法使用一个Func<TSource, TKey> ,所以你可以这样重写你的函数:

 List<Student> QueryStudents<TKey>(Func<Student, TKey> orderBy) { return existingStudents.OrderByDescending(orderBy).ToList(); } 

OrderByDescending还有其他一些重载,它们需要一个Expression<Func<TSource, TKey>>和/或IComparer<TKey> 。 你也可以看看这些,看看他们是否提供任何使用。

我唯一的解决scheme是由neoGeneva发布在这里https://gist.github.com/neoGeneva/1878868

我会重新发布他的代码,因为它运行良好,我不希望它在互联网中丢失!

  public static IQueryable<T> OrderBy<T>(this IQueryable<T> source, string sortExpression) { if (source == null) throw new ArgumentNullException("source", "source is null."); if (string.IsNullOrEmpty(sortExpression)) throw new ArgumentException("sortExpression is null or empty.", "sortExpression"); var parts = sortExpression.Split(' '); var isDescending = false; var propertyName = ""; var tType = typeof(T); if (parts.Length > 0 && parts[0] != "") { propertyName = parts[0]; if (parts.Length > 1) { isDescending = parts[1].ToLower().Contains("esc"); } PropertyInfo prop = tType.GetProperty(propertyName); if (prop == null) { throw new ArgumentException(string.Format("No property '{0}' on type '{1}'", propertyName, tType.Name)); } var funcType = typeof(Func<,>) .MakeGenericType(tType, prop.PropertyType); var lambdaBuilder = typeof(Expression) .GetMethods() .First(x => x.Name == "Lambda" && x.ContainsGenericParameters && x.GetParameters().Length == 2) .MakeGenericMethod(funcType); var parameter = Expression.Parameter(tType); var propExpress = Expression.Property(parameter, prop); var sortLambda = lambdaBuilder .Invoke(null, new object[] { propExpress, new ParameterExpression[] { parameter } }); var sorter = typeof(Queryable) .GetMethods() .FirstOrDefault(x => x.Name == (isDescending ? "OrderByDescending" : "OrderBy") && x.GetParameters().Length == 2) .MakeGenericMethod(new[] { tType, prop.PropertyType }); return (IQueryable<T>)sorter .Invoke(null, new object[] { source, sortLambda }); } return source; } 

我迟到了晚会,但这些解决scheme都没有为我工作。 我急于尝试System.Linq.Dynamic,但我无法在Nuget上find,也许折旧? 无论哪种方式…

这是我想出的解决scheme。 我需要dynamic地使用OrderByOrderByDescendingOrderBy> ThenBy的混合

我简单地为我的列表对象创build了一个扩展方法,我知道有一点哈克…我不会推荐这个,如果这是我做了很多,但它是一个好的。

 List<Employee> Employees = GetAllEmployees(); foreach(Employee oEmployee in Employees.ApplyDynamicSort(eEmployeeSort)) { //do stuff } public static IOrderedEnumerable<Employee> ApplyDynamicSort(this List<Employee> lEmployees, Enums.EmployeeSort eEmployeeSort) { switch (eEmployeeSort) { case Enums.EmployeeSort.Name_ASC: return lEmployees.OrderBy(x => x.Name); case Enums.EmployeeSort.Name_DESC: return lEmployees.OrderByDescending(x => x.Name); case Enums.EmployeeSort.Department_ASC_Salary_DESC: return lEmployees.OrderBy(x => x.Department).ThenByDescending(y => y.Salary); default: return lEmployees.OrderBy(x => x.Name); } } 
  • 将金块包Dynamite添加到您的代码中

  • 添加命名空间Dynamite.Extensions例如:使用Dynamite.Extensions;

  • 通过像任何SQL查询一样的查询来提供sorting例如:students.OrderBy(“City DESC,Address”)。ToList();