【问题标题】:dynamic sort in linqlinq中的动态排序
【发布时间】:2012-09-19 13:34:24
【问题描述】:

请考虑这种情况:

我有一个包含大约 50 个字段的类列表。我想要一个组合框,用户可以根据字段列表的排序进行选择。例如,如果用户选择“F1”,则列表根据“F1”进行排序。

我不想对每个字段都使用if-else 进行排序。我看到了这个主题:

Sorting a gridview when databinding a collection or list of objects

但我不能使用它的答案。我如何使用Expression Tree 来达到这个目的?

谢谢

编辑 1)

根据亲爱的@Thom Smith 的回答,我写了这段代码:

 using (NorthwindModel1.NorthwindEntities2 ent = new NorthwindModel1.NorthwindEntities2())
    {
        var query = from o in ent.Orders
                    where o.OrderID < 10257
                    select o;

        query.OrderBy("CustomerID", SortDirection.Ascending);

        GridView1.DataSource = query;
        GridView1.DataBind();
    }

但它没有排序。如果我以这种方式编写该代码:

GridView1.DataSource = query.OrderBy(o=>o.CustomerID);

它正在排序。问题出在哪里?

【问题讨论】:

标签: c# linq c#-4.0 lambda expression-trees


【解决方案1】:

这是我使用的方法:

private IQueryable<T> OrderQuery<T>(IQueryable<T> query, OrderParameter orderBy)
{
    string orderMethodName = orderBy.Direction == SortDirection.Ascending ? "OrderBy" : "OrderByDescending";
    Type t = typeof(T);

    var param = Expression.Parameter(t, "shipment");
    var property = t.GetProperty(orderBy.Attribute);

    /* We can't just call OrderBy[Descending] with an Expression
     * parameter because the second type argument to OrderBy is not
     * known at compile-time.
     */
    return query.Provider.CreateQuery<T>(
        Expression.Call(
            typeof(Queryable),
            orderMethodName,
            new Type[] { t, property.PropertyType },
            query.Expression,
            Expression.Quote(
                Expression.Lambda(
                    Expression.Property(param, property),
                    param))
        ));
}

OrderParameter 只是一个带有属性和方向的结构体。

编辑:补充说明。

这个方法来自我的DynamicOrderList 类,它是OrderParameter 对象的列表。如果您只需要按一个字段排序,那么您可以稍微简化一下:

private IQueryable<T> OrderByDynamic<T>(this IQueryable<T> query, string attribute, SortDirection direction)
{
    try
    {
        string orderMethodName = direction == SortDirection.Ascending ? "OrderBy" : "OrderByDescending";
        Type t = typeof(T);

        var param = Expression.Parameter(t);
        var property = t.GetProperty(attribute);

        return query.Provider.CreateQuery<T>(
            Expression.Call(
                typeof(Queryable),
                orderMethodName,
                new Type[] { t, property.PropertyType },
                query.Expression,
                Expression.Quote(
                    Expression.Lambda(
                        Expression.Property(param, property),
                        param))
            ));
    }
    catch (Exception) // Probably invalid input, you can catch specifics if you want
    {
        return query; // Return unsorted query
    }
}

然后像这样使用它:

myQuery = myQuery.OrderByDynamic("name", SortDirection.Ascending);

编辑 2:

public IQueryable<T> OrderBy<T>(this IQueryable<T> query, string attribute, SortDirection direction)
{
    return ApplyOrdering(query, attribute, direction, "OrderBy");
}

public IQueryable<T> ThenBy<T>(this IQueryable<T> query, string attribute, SortDirection direction)
{
    return ApplyOrdering(query, attribute, direction, "ThenBy");
}

private IQueryable<T> ApplyOrdering<T>(IQueryable<T> query, string attribute, SortDirection direction, string orderMethodName)
{
    try
    {
        if (direction == SortDirection.Descending) orderMethodName += "Descending";

        Type t = typeof(T);

        var param = Expression.Parameter(t);
        var property = t.GetProperty(attribute);

        return query.Provider.CreateQuery<T>(
            Expression.Call(
                typeof(Queryable),
                orderMethodName,
                new Type[] { t, property.PropertyType },
                query.Expression,
                Expression.Quote(
                    Expression.Lambda(
                        Expression.Property(param, property),
                        param))
            ));
    }
    catch (Exception) // Probably invalid input, you can catch specifics if you want
    {
        return query; // Return unsorted query
    }
}

还有:

myQuery=myQuery.OrderBy("name", SortDirection.Ascending).ThenBy("date", SortDirection.Descending);

【讨论】:

  • thatnks 你怎么用这个?
  • 能否请您发布根据多个字段排序的方法。谢谢亲爱的朋友
【解决方案2】:

OrderBy 不进行就地排序。它返回一个序列,在评估时将被排序。这通常是惰性完成的,意思是:在枚举之前,它什么都不做。您当前的代码只是丢弃了这个最重要的返回值。修复很简单:捕获返回值:

query = query.OrderBy("CustomerID", SortDirection.Ascending);

注意:同样,应用“Where”不会过滤现有数据:它返回一个序列,枚举时会被过滤。因此,如果您进行过滤,您会得到类似的结果:

query = query.Where(...);

【讨论】:

    【解决方案3】:

    这是我的热门话题,使用Enumerable+Reflection 而不是查询:

    list.OrderBy(x => {
                           var prop = x.GetType().GetProperty(sortFieldName);
                           return prop.GetValue(x);
                       });
    
    if (!isSortAsc) list.Reverse();
    

    【讨论】:

    • 更好的是获得 'var prop = x.GetType().GetProperty(sortFieldName);' lambda 表达式之外的部分
    • 适用于旧 (3.5) 框架的较短版本:list.OrderBy(x => x.GetType().GetProperty(sortFieldName).GetValue(x));尽管如此,可以通过将 GetType/GetProperty 放在外部变量中进​​行优化。
    【解决方案4】:

    希望对您有所帮助。它对我来说可以动态过滤 C# 列表

    string jtSorting = "ContactName";
    DashboardModel Sup = new DashboardModel();
    List<Applicant> lstSup = Sup.GetonBoard();
    lstSup = lstSup.AsQueryable().SortBy(jtSorting).ToList();
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-08
      • 2011-04-28
      • 1970-01-01
      相关资源
      最近更新 更多