【问题标题】:create a generic method that sorts List<T> collections创建一个对 List<T> 集合进行排序的通用方法
【发布时间】:2010-09-01 05:42:28
【问题描述】:

我以前做的是创建一个 case switch,以这种格式对我的 LINQ 进行排序:

List<products> productList = GetAllLists();

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

从长远来看,这会变得很麻烦。

我希望有一个通用方法,您可以简单地使用它来排序这样的 List 集合,并帮助您切换要排序的属性.. 像这样:

return SortListCollection(productsList, Name);

【问题讨论】:

  • 您在此处询问的内容与OrderBy 已经提供的内容有何不同?您是否希望能够传递字符串而不是 Func&lt;T, TResult&gt;
  • 嗨,丹,我猜可能差不多。
  • 直接传递Func&lt;T,R&gt;,正如 Dan 所提到的,会很快并且允许编译时检查。使用字符串会很慢(呃),并且更容易出现运行时错误。

标签: c# linq generics lambda


【解决方案1】:

你不需要为此使用反射,你可以使用表达式树来做到这一点,这样会快得多。 Here's a blog post 描述了该过程,但剪切'n'paste 示例是:

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

【讨论】:

    【解决方案2】:

    需要能够传递字符串吗?传入Func&lt;T,TResult&gt; 委托将快速、灵活并允许运行时检查;不会传入string

    您甚至可以准备好一堆预定义的委托:

    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;
    

    当然,如果您愿意,您可以将其全部封装在您自己的方法中,但该方法只是封装OrderBy 调用是多余的单行代码。

    【讨论】:

      【解决方案3】:

      已解决:

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

      【讨论】:

      • 这种方法性能会很差。有一个更快的方法。给我一点时间,我会尽快发布。
      • 只需添加 PropertyInfo 的缓存 (cc.GetType().GetProperty(propertyName)) 就可以了。
      • 好的,亚历克斯,我想我已经得到了答案。感谢所有帮助过的人!
      • 此外,这非常脆弱。一旦您更改了属性的名称,您的代码就会出现运行时异常,并且您不会在编译时被告知它(可能会通过一条规则来缓解这种情况,即只发送您通过 @ 获得的属性987654322@构造)
      【解决方案4】:

      使用反射构建一个可以按属性名称进行比较的比较器类。然后实例化这个类并将它的比较函数传递给List.Sort

      【讨论】:

        猜你喜欢
        • 2021-12-25
        • 1970-01-01
        • 2013-02-25
        • 1970-01-01
        • 2012-01-03
        • 2019-07-02
        • 2011-03-09
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多