使用LINQ按子类的属性对父类列表进行排序

时间:2017-03-20 08:29:07

标签: c# linq sorting generics

我有一个具有以下结构的课程

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

带有子类

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

因此,我们的想法是根据SortFields类属性中的值对List进行排序。

我能想到的最基本的解决方案就是做这样的事情

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--
               }
           }
}

理想情况下,我希望能够在sortby方法中将sortBy作为参数传递,虽然我确实在互联网上找到了几个解决方案,但它们似乎无法对基类列表进行排序子类属性。

有没有办法可以将子类属性作为参数传递,并且能够将列表排序为父类?

3 个答案:

答案 0 :(得分:2)

按属性和lambda将排序存储在字典Dictionary<string,Func<DisplayItem,string>> dct中并传递给方法:

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;
    }
}

所以你会把你的lambda存储起来:

dct["ProductNumber"] = x => x.SortFields.ProductNumber;

答案 1 :(得分:2)

你可以这个代码, 获得一个函数来选择要排序的字段:

例如,代码将如下所示: 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));
            }   

        }

答案 2 :(得分:0)

这可能会对您有所帮助。

group

使用..

    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;
    }

enter image description here