Linq Заказать по списку (из myObjects)
Как мне упорядочить по переданному строковому значению в моем списке объектов? мне нужно делать подкачки и сортировку по моим объектам List (Of), пейджинг - это не проблема, но я не знаю, кто получит заказ By для работы.
Вот что я сейчас делаю, и он отлично работает:
Return returnReports.Skip(PageSize * (PageNumber-1)).Take(PageSize).ToList()
Как мне заставить это работать?
Return returnReports.OrderBy(SortColumn).Skip(skip).Take(PageSize).ToList()
SortColumn - это переданное строковое значение
Ответы
Ответ 1
В. Б.
Module OrderByExtensions
<System.Runtime.CompilerServices.Extension()> _
Public Function OrderByPropertyName(Of T)(ByVal e As IEnumerable(Of T), ByVal propertyName As String) As IOrderedEnumerable(Of T)
Dim itemType = GetType(T)
Dim prop = itemType.GetProperty(propertyName)
If prop Is Nothing Then Throw New ArgumentException("Object does not have the specified property")
Dim propType = prop.PropertyType
Dim funcType = GetType(Func(Of ,)).MakeGenericType(itemType, propType)
Dim parameter = Expression.Parameter(itemType, "item")
Dim exp = Expression.Lambda(funcType, Expression.MakeMemberAccess(parameter, prop), parameter)
Dim params = New Object() {e, exp.Compile()}
Return DirectCast(GetType(OrderByExtensions).GetMethod("InvokeOrderBy", Reflection.BindingFlags.Static Or Reflection.BindingFlags.NonPublic).MakeGenericMethod(itemType, propType).Invoke(Nothing, params), IOrderedEnumerable(Of T))
End Function
Private Function InvokeOrderBy(Of T, U)(ByVal e As IEnumerable(Of T), ByVal f As Func(Of T, U)) As IOrderedEnumerable(Of T)
Return Enumerable.OrderBy(e, f)
End Function
End Module
С#
public static class OrderByExtensions
{
public static IOrderedEnumerable<T> OrderByPropertyName<T>(this IEnumerable<T> e, string name)
{
var itemType = typeof(T);
var prop = itemType.GetProperty(name);
if (prop == null) throw new ArgumentException("Object does not have the specified property");
var propType = prop.PropertyType;
var funcType = typeof(Func<,>).MakeGenericType(itemType, propType);
var parameter = Expression.Parameter(itemType, "item");
var memberAccess = Expression.MakeMemberAccess(parameter, prop);
var expression = Expression.Lambda(funcType, memberAccess, parameter);
var x = typeof(OrderByExtensions).GetMethod("InvokeOrderBy", BindingFlags.Static | BindingFlags.NonPublic);
return (IOrderedEnumerable<T>)x.MakeGenericMethod(itemType, propType).Invoke(null, new object[] { e, expression.Compile() });
}
static IOrderedEnumerable<T> InvokeOrderBy<T, U>(IEnumerable<T> e, Func<T, U> f)
{
return e.OrderBy(f);
}
}
Ответ 2
Передайте столбец сортировки как функцию.
Итак, это будет
public SomeList Foo(Function<Foo, bool> sortFunction, int skip, int PageSize)
{
return returnReports.OrderBy(sortFunction).Skip(skip).Take(PageSize).ToList();
}
Назовите его так:
SomeList(f => f.Bar, 5, 10);
Ответ 3
если вы работаете с базой данных в качестве источника данных, вы можете использовать Dynamic LINQ, который позволяет вам указывать параметры для предложение Where как строка.
Если вы работаете с "Linq to objects", вам нужно создать функцию лямбда, которая динамически передается в качестве аргумента. Вы можете сделать это, используя методы "Expression.Xyz" для построения дерева выражений, а затем с помощью метода "Compile", который превращает дерево выражений в вызываемый делегат (типа Func < > ), который вы можете использовать в качестве аргумента для Где. Пример построения дерева выражений можно найти в другом SO-потоке здесь.
Ответ 4
Вы не можете сделать это (легко), если вы просто передали строку. У вас может быть карта от String до Func<IEnumerable<Report>, IEnumerable<Report>>
, например. (в С#)
// Horrible type. Ick.
private static readonly
Dictionary<string, Func<IEnumerable<Report>,IEnumerable<Report>>>
Orderings =
new Dictionary<string, Func<IEnumerable<Report>,IEnumerable<Report>>>
{
{ "FirstColumn", (IEnumerable<Report> reports) =>
reports.OrderBy(report => report.FirstColumn) },
{ "SecondColumn", (IEnumerable<Report> reports) =>
reports.OrderBy(report => report.SecondColumn) },
(etc)
};
Затем используйте:
// For production usage, include some error checking!
return Orderings[sortColumn].Skip(skip).Take(pageSize).ToList();
Если вы можете передать SortColumn
в качестве подходящего Func
(возможно, создав свой общий метод), чтобы избежать беспорядка здесь.
Ответ 5
Вместо .OrderBy вы можете использовать .Sort. Просто создайте класс Comparer для вашего объекта, например this.
public class FooComparer : IComparer<Foo>
{
private readonly string _sortBy;
private readonly bool _sortDesc;
public FooComparer(string sortBy)
{
_sortBy = sortBy.ToLower();
_sortDesc = _sortBy.EndsWith(" desc");
_sortBy = _sortBy.Replace(" asc", string.Empty).Replace(" desc", string.Empty);
}
//implement IComparer method
public int Compare(Foo x, Foo y)
{
int ret = 0;
switch (_sortBy)
{
//must match lowercase sortname
case "date":
ret = DateTime.Compare(x.SomeDate, y.SomeDate);
break;
//other properties you can sort by as above...
}
//if there is a tie, break it consistently - this will be specific to your object
if (ret == 0)
{
ret = (DateTime.Compare(x.InsertDate, y.InsertDate));
}
if (_sortDesc)
{
ret *= -1;
}
return ret;
}
}
Затем вызов sort будет выглядеть следующим образом:
Return Foo.Sort(new FooComparer(sortName + " " + sortOrder)
Итак, ваш стал бы (порядок сортировки по умолчанию возрастает, если он не указан):
returnReports.Sort(new ReturnReportsComparer(SortColumn));
return returnReports.Skip(skip).Take(PageSize).ToList()