【问题标题】:Sort List of parent class by property of subclass using LINQ使用 LINQ 按子类的属性对父类列表进行排序
【发布时间】:2017-03-20 08:29:07
【问题描述】:

我有一个具有以下结构的类

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 作为参数传递给 orderby 方法,虽然我确实在互联网上找到了一些解决方案,但它们似乎无法根据子类属性。

有没有办法我们可以将子类属性作为参数传递并能够对父类列表进行排序?

【问题讨论】:

标签: c# linq sorting generics


【解决方案1】:

将您的排序按属性和 lambda 存储在字典 Dictionary&lt;string,Func&lt;DisplayItem,string&gt;&gt; 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;

【讨论】:

    【解决方案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));
                }   
    
            }
    

    【讨论】:

    • 我认为 OP 希望能够按属性名称(字符串)进行排序。否则为什么我需要这种方法而我可以简单地做到list.OrderBy(x =&gt; x.SortFields.ProductNumber)
    【解决方案3】:

    这可能对你有帮助。

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

    使用..

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-12
      • 1970-01-01
      • 1970-01-01
      • 2021-11-12
      • 2020-03-28
      相关资源
      最近更新 更多