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()