linq中的動態排序

c# c#-4.0 expression-trees lambda linq

請考慮這種情況:

我有一個包含大約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();
    }

但它沒有排序。如果我用這種方式編寫代碼:

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

它是排序的。哪裡有問題?

一般承認的答案

OrderBy不進行就地排序。它返回一個序列, 在評估時將對其進行排序。這通常是懶惰地進行的,這意味著:直到它被枚舉,它什麼都不做 。您當前的代碼只會丟棄這個非常重要的返回值。修復很簡單:捕獲返回值:

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

注意:類似地,應用“Where”不會過濾現有數據:它返回枚舉時過濾的序列。所以,如果你過濾你有類似的:

query = query.Where(...);

熱門答案

這是我用於此的方法:

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


許可下: CC-BY-SA with attribution
不隸屬於 Stack Overflow
這個KB合法嗎? 是的,了解原因
許可下: CC-BY-SA with attribution
不隸屬於 Stack Overflow
這個KB合法嗎? 是的,了解原因