【问题标题】:Sort lists by using LambdaExpression in "complex types"在“复杂类型”中使用 LambdaExpression 对列表进行排序
【发布时间】:2016-05-25 14:34:04
【问题描述】:

每个人。在过去的几个小时里,我尝试通过 Google 找到答案并使用即时窗口进行绝望的测试,但我认为我没有提出正确的问题。

我的应用程序中有一个 OrderByExtender,我使用它来进行排序,只使用属性名称和一个布尔值来判断它是 ASC 还是 DESC 排序。

    public static IOrderedEnumerable<T> OrderBy<T>(this IEnumerable<T> collection, string key, bool isAscending)
    {
        LambdaExpression sortLambda = BuildLambda<T>(key);

        if (isAscending)
            return collection.OrderBy((Func<T, object>)sortLambda.Compile());
        else
            return collection.OrderByDescending((Func<T, object>)sortLambda.Compile());
    }

    private static LambdaExpression BuildLambda<T>(string key)
    {
        ParameterExpression TParameterExpression = Expression.Parameter(typeof(T), "p");
        LambdaExpression sortLambda = Expression.Lambda(Expression.Convert(Expression.Property(TParameterExpression, key), typeof(object)), TParameterExpression);
        return sortLambda;
    }

当我使用通用类型属性(字符串、整数等)时,它就像一个魅力。但现在我想出了以下场景:我有一个名为 BusinessOrder 的对象,其中有一个类型为 Quarter 的属性。此 Quarter 对象具有三个属性:Year(int)、Quarter(int) 和 Abbreviation(string)。我必须使用 Abbreviation 属性执行 OrderBy。换句话说,我必须这样做:

BusinessOrderList.OrderBy(b => b.Quarter.Abbreviation);

但是我想把这种排序可能性放在我的扩展器中,通过传递像“Quarter.Abbreviation”之类的 key 参数,扩展器方法知道这是将属性放入内部的问题一个“复杂的对象”。

我相信我可以在创建 sortLambda 变量的“Expression.Lambda”方法中做一些事情,但我不知道如何使用 Expressions 来复制这种行为。有人能帮我吗?提前致谢。

【问题讨论】:

    标签: c# linq sorting lambda linq-expressions


    【解决方案1】:

    您无法一步访问复杂的属性。您必须递归地构建表达式链:

        private Func<TInput, object> BuildLambda<TInput>(string complexPropertyPath)
        {
            var parameter = Expression.Parameter(typeof(TInput), "p");
    
            var propertyPathParts = complexPropertyPath.Split('.');
            MemberExpression complexPropertyAccessExpression = null;
            foreach (var propertyPathPart in propertyPathParts)
            {
                complexPropertyAccessExpression = complexPropertyAccessExpression == null
                    ? Expression.Property(parameter, propertyPathPart)
                    : Expression.Property(complexPropertyAccessExpression, propertyPathPart);
            }
    
            var lambda = (Func<TInput, object>)Expression.Lambda(complexPropertyAccessExpression, parameter).Compile();
    
            return lambda;
        }
    

    【讨论】:

    • 漂亮!再好不过了!这是我想做的事情,只是没有所需的知识!谢谢!
    【解决方案2】:

    如果可能,我建议将string key 参数替换为Expression&lt;Func&lt;T, object&gt;&gt; key 参数。这样,您的函数调用可以是BusinessOrderList.OrderBy(b =&gt; b.Quarter.Abbreviation);,正如您所描述的那样。由于所有 OrderBy/OrderByDescending 方法无论如何都接受此表达式作为字符串的替代,我看不出将 key 保留为字符串有什么好处。

    【讨论】:

      【解决方案3】:

      您可以通过Func 对您的收藏进行排序

      public static IOrderedEnumerable<T> OrderBy<T>(this IEnumerable<T> collection,
                                 Func<IEnumerable<T>,IOrderedEnumerable<T>> OrderBy)
      {
          if(OrderBy != null)
              return OrderBy(collection);
          return collection; 
      }
      

      你必须这样称呼它

      {
          Func<IEnumerable<Book>,IOrderedEnumerable<Book>> sort = 
          list => list.OrderBy(B=>B.Author.Name).ThenByDescending(B=>B.Title) ; 
      
          List.OrderBy(sort);
      
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-08-05
        • 2019-06-25
        • 1970-01-01
        • 2016-03-01
        • 2019-05-03
        • 1970-01-01
        • 2016-12-25
        • 1970-01-01
        相关资源
        最近更新 更多