2

I have a class with the following structure

public class DisplayItem 
{
   public string Id { get; set; }
   public SortFields SortFields { get; set; }
}

with a sub class

public class SortFields
    {
        public string ProductNumber { get; set; }
        public DateTime DateOfUpload { get; set; }
    }

So the idea is to sort a List based on the values in the SortFields class properties.

The most basic solution i can think of is to do something like this

public IEnumerable<DisplayItem> Sort(IEnumerable<DisplayItem> source, string sortBy, SortDirection sortDirection)
       {

           switch (sortBy)
           {
                case "Product Number":
                   switch (sortDirection)
                   {
                        case SortDirection.Ascending:
                           return source.OrderBy(x => x.SortFields.ProductNumber);
                        case SortDirection.Descending:
                            return source.OrderByDescending(x => x.SortFields.ProductNumber);
                   }
                case "Uploaded Date":
               {
                        //--do--
               }
           }
}

Ideally i would like to be able to pass the sortBy as a parameter in the orderby method and while i did find a couple of solutions on the internet , they dont seem to be able to sort the list of the base class based on subclass property.

is there a way that we can pass the sub class property as a parameter and be able to sort the list the parent class?

Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555
Pankaj Kumar
  • 1,748
  • 6
  • 28
  • 41
  • Possible duplicate of [Dynamic LINQ OrderBy on IEnumerable](http://stackoverflow.com/questions/41244/dynamic-linq-orderby-on-ienumerablet) – ASh Mar 20 '17 at 08:30
  • if you want to sort by that property you must implement the `IComparable` interface – Alex Mar 20 '17 at 08:35

3 Answers3

2

Store your sort by properties and lambda in a dictionary Dictionary<string,Func<DisplayItem,string>> dct and pass into the method:

public IEnumerable<DisplayItem> Sort(IEnumerable<DisplayItem> source, string sortBy, Dictionary<string,Func<DisplayItem,string>> dct, SortDirection sortDirection)
{
    switch (sortDirection)
    {
        case SortDirection.Ascending:
            return source.OrderBy(x => dct[sortBy]);
        case SortDirection.Descending:
            return source.OrderByDescending(x => dct[sortBy]);
        default:
            return null;
    }
}

So you would store your lambda like:

dct["ProductNumber"] = x => x.SortFields.ProductNumber;
Sadique
  • 22,572
  • 7
  • 65
  • 91
2

You can you this code, that get a function to choose on which field to sort:

For example, code will be like this: Sort(list, (x) => x.SortFields.ProductNumber, true);

public static IEnumerable<T> Sort(IEnumerable<T> source, Func<T,string> sortBy, bool isUp) where T : new()
        {
            if(isUp)
            {
                return source.OrderBy(a => sortBy.Invoke(a));
            }

            else 
            {
                return source.OrderByDescending(a => sortBy.Invoke(a));
            }   

        }
Ygalbel
  • 5,214
  • 1
  • 24
  • 32
  • 1
    I think OP wants to be able to sort by Property Name (string). Otherwise why would I need this method while I can do it simply `list.OrderBy(x => x.SortFields.ProductNumber)` – sallushan Mar 20 '17 at 08:55
0

this is may be helpful you.

    private static readonly MethodInfo OrderByMethod = typeof(Queryable).GetMethods().Single(method => method.Name == "OrderBy" && method.GetParameters().Length == 2);

    private static readonly MethodInfo OrderByDescendingMethod = typeof(Queryable).GetMethods().Single(method => method.Name == "OrderByDescending" && method.GetParameters().Length == 2);

    static IQueryable<T> OrderByQuery<T>(IQueryable<T> source, string propertyName, SortDirection direction)
    {
        string[] memberTree = propertyName.Split('.');
        Expression ex = null;
        Type currentType = typeof(T);
        ParameterExpression parameterExpression = Expression.Parameter(currentType);
        for (int i = 0; i < memberTree.Length; i++)
        {
            ex = Expression.Property(ex != null ? ex : parameterExpression, memberTree[i]);
        }
        LambdaExpression lambda = Expression.Lambda(ex, parameterExpression);
        MethodInfo genericMethod  =
        direction == SortDirection.Descending
            ? OrderByDescendingMethod.MakeGenericMethod(currentType, ex.Type)
            : OrderByMethod.MakeGenericMethod(currentType, ex.Type);
        object ret = genericMethod.Invoke(null, new object[] { source, lambda });
        return (IQueryable<T>)ret;
    }

using..

public class A { public B MemberB { get; set; }}
public class B { public string Name { get; set; }}
List<A> listt = new List<A>{
            new A{ MemberB = new B{Name ="a"}},
            new A{ MemberB = new B{Name ="b"}},
            new A{ MemberB = new B{Name ="u"}},
            new A{ MemberB = new B{Name ="l"}},
            new A{ MemberB = new B{Name ="i"}}
};
var rr = OrderByQuery(listt.AsQueryable(), "MemberB.Name", SortDirection.Ascending).ToList();

enter image description here

levent
  • 3,464
  • 1
  • 12
  • 22