linq中的动态排序

Ari*_*ian 7 c# linq lambda expression-trees c#-4.0

请考虑这种情况:

我有一个包含大约50个字段的类的列表.我想要一个用户可以根据字段列表进行排序的Combobox.例如,如果用户选择"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();
    }
Run Code Online (Sandbox Code Playgroud)

但它没有排序.如果我用这种方式编写代码:

GridView1.DataSource = query.OrderBy(o=>o.CustomerID);
Run Code Online (Sandbox Code Playgroud)

它是排序的.问题出在哪儿?

Tho*_*ith 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))
        ));
}
Run Code Online (Sandbox Code Playgroud)

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
    }
}
Run Code Online (Sandbox Code Playgroud)

然后使用它像:

myQuery = myQuery.OrderByDynamic("name", SortDirection.Ascending);
Run Code Online (Sandbox Code Playgroud)

编辑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
    }
}
Run Code Online (Sandbox Code Playgroud)

和:

myQuery=myQuery.OrderBy("name", SortDirection.Ascending).ThenBy("date", SortDirection.Descending);
Run Code Online (Sandbox Code Playgroud)


Mar*_*ell 5

OrderBy不进行就地排序.它返回一个序列,在评估时将对其进行排序.这通常是懒惰地进行的,这意味着:直到它被枚举,它什么都不做.您当前的代码只是丢弃这个非常重要的返回值.修复很简单:捕获返回值:

query = query.OrderBy("CustomerID", SortDirection.Ascending);
Run Code Online (Sandbox Code Playgroud)

注意:类似地,应用"Where"不会过滤现有数据:它返回枚举时过滤的序列.所以,如果你过滤你有类似的:

query = query.Where(...);
Run Code Online (Sandbox Code Playgroud)