简体   繁体   中英

create a generic method that sorts List<T> collections

What I used to do is create a case switch that sorts my LINQ in this format:

List<products> productList = GetAllLists();

switch (sortBy)
{
  case "name":
     return productsList.OrderBy(pl => pl.Name);
  case "date":
     return productsList.OrderBy(pl => pl.DateCreate);
}

which, in the long run, becomes cumbersome.

I wanted to have a generic method that you simply use to sort out List collections like these and will help you toggle which property to sort by.. something like this:

return SortListCollection(productsList, Name);

You don't need to use reflection for this, you can do it using expression trees, which will be much faster. Here's a blog post that describes the process, but a cut'n'paste sample is:

public static IQueryable<T> SortBy<T>(this IQueryable<T> source, string propertyName)
{
    var parameter = Expression.Parameter(source.ElementType, String.Empty);
    var property = Expression.Property(parameter, propertyName);
    var lambda = Expression.Lambda(property, parameter);

    var methodCallExpression = Expression.Call(typeof(Queryable), "OrderBy",
        new Type[] { source.ElementType, property.Type },
        source.Expression, Expression.Quote(lambda));

    return source.Provider.CreateQuery<T>(methodCallExpression);
}

Do you need to be able to pass in strings? Passing in a Func<T,TResult> delegate will be fast, flexible, and allow runtime checking; passing in a string won't be.

You could even have a bunch of predefined delegates ready-to-go:

var sortedByName = productList.OrderBy(NameSelector);
var sortedByDate = productList.OrderBy(DateCreatedSelector);
var sortedByCustom = productList.OrderBy(p => p.SomeOtherProperty);

// ...

// predefined delegates
public static readonly Func<Product, string> NameSelector = p => p.Name;

public static readonly Func<Product, DateTime> DateCreatedSelector =
                                                     p => p.DateCreated;

And, of course, you could wrap it all up in your own method if you wanted to, but that method would be a superfluous one-liner just wrapping the OrderBy call.

Solved:

private List<T> SortList<T>(List<T> collection, SortOrder order, string propertyName) where T : class
        {
            if (order == SortOrder.Descending)
            {
                return collection.OrderByDescending(cc => cc.GetType().GetProperty(propertyName).GetValue(cc, null)).ToList();
            }

            return collection.OrderBy(cc => cc.GetType().GetProperty(propertyName).GetValue(cc, null)).ToList();
        }

Use reflection to build a comparer class that can compare by property name. Then instantiate this class and pass it's compare function to List.Sort

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM