8

请考虑这种情况:

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

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

对集合或对象列表进行数据绑定时对网格视图进行排序

但我不能使用它的答案。我如何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);

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

4

4 回答 4

8

这是我用于此的方法:

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);
于 2012-09-19T13:39:50.413 回答
5

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

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

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

query = query.Where(...);
于 2012-09-22T16:17:35.237 回答
2

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

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

if (!isSortAsc) list.Reverse();
于 2017-05-19T03:18:20.543 回答
-1

希望它会有所帮助。它对我有用,可以动态过滤 C# 列表

string jtSorting = "ContactName";
DashboardModel Sup = new DashboardModel();
List<Applicant> lstSup = Sup.GetonBoard();
lstSup = lstSup.AsQueryable().SortBy(jtSorting).ToList();
于 2014-10-22T11:53:50.947 回答