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)
它是排序的.问题出在哪儿?
这是我用于此的方法:
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)
OrderBy不进行就地排序.它返回一个序列,在评估时将对其进行排序.这通常是懒惰地进行的,这意味着:直到它被枚举,它什么都不做.您当前的代码只是丢弃这个非常重要的返回值.修复很简单:捕获返回值:
query = query.OrderBy("CustomerID", SortDirection.Ascending);
Run Code Online (Sandbox Code Playgroud)
注意:类似地,应用"Where"不会过滤现有数据:它返回枚举时过滤的序列.所以,如果你过滤你有类似的:
query = query.Where(...);
Run Code Online (Sandbox Code Playgroud)