Как динамически указать аргумент 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();
10 ответов:
вот возможность использования отражения...
var param = "Address"; var propertyInfo = typeof(Student).GetProperty(param); var orderByAddress = items.OrderBy(x => propertyInfo.GetValue(x, null));
вы можете использовать немного отражения, чтобы построить дерево выражений следующим образом (это метод расширения):
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
, будет сортировать в порядке убывания; в противном случае, будет сортировать в порядке возрастания.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);
вот что я придумал для борьбы с условным убыванию. Вы можете объединить это с другими методами генерации
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
, Как вы просили в вашем вопросе, но он все еще может работать для вас.The
OrderByDescending
метод принимаетFunc<TSource, TKey>
, Так что вы можете переписать функцию таким образом:List<Student> QueryStudents<TKey>(Func<Student, TKey> orderBy) { return existingStudents.OrderByDescending(orderBy).ToList(); }
есть и другие перегрузки для
OrderByDescending
Как хорошо, что взятьExpression<Func<TSource, TKey>>
и/илиIComparer<TKey>
. Вы также можете заглянуть в них и посмотреть, если они предлагают вам что-нибудь полезное.
единственное решение, которое сработало для меня, было опубликовано здесь 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; }
для расширения на ответ @Icarus: Если вы хотите, чтобы возвращаемый тип метода расширения был IOrderedQueryable вместо IQueryable, вы можете просто привести результат следующим образом:
public static IOrderedQueryable<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 (IOrderedQueryable<TEntity>)source.Provider.CreateQuery<TEntity>(resultExpression); }
добавить самородок пакет Динамит код
добавить пространство имен Динамит.Расширения Например: с помощью динамита.Расширения;
дать порядок по запросу, как и любой SQL-запрос Например: студенты.OrderBy ("город DESC, адрес").ToList ();
Я опоздал на вечеринку, но ни одно из этих решений работал для меня. Я очень хотел попробовать систему.В LINQ.Динамично, но я не мог найти это на Nuget, может быть, обесценилось? В любом случае...
вот решение, которое я придумал. Мне нужно было динамически использовать смесь OrderBy,OrderByDescending и OrderBy > ThenBy.
Я просто создал метод расширения для моего объекта списка, немного хаки я знаю... Я бы не рекомендовал если это было то, что я делал много, но это хорошо для разовых.
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); } }