我正在尝试动态构建一个表达式树,以便可以更改字典中包含的数据的排序顺序。有很多关于动态指定要排序的列的信息,但这并不是我真正遇到的问题。我正在与构建表达式树的MethodCallExpression进行斗争。
在本例中,我简化了字典:
Dictionary<string, Dictionary<int, int>> data = new Dictionary<string, Dictionary<int, int>>();
我试图建立一个类似这样的表达式:
data.OrderByDescending(someValue)
.ThenByDescending(someothervalue)
.ThenByDescending(anothervalue)...etc
其中“thenby”或“thenbydranceding”子句的数目是在运行时确定的。
举一个例子,需要按4,3,1进行排序。我已经确定(我认为)以下表达式可以转换为我的3个排序顺序:
Expression<Func<KeyValuePair<string, Dictionary<int, int>>, int>> ex1 = (r => r.Value[4]);
Expression<Func<KeyValuePair<string, Dictionary<int, int>>, int>> ex2 = (r => r.Value[3]);
Expression<Func<KeyValuePair<string, Dictionary<int, int>>, int>> ex2 = (r => r.Value[1]);
所以在编译时,我可以编写这个表达式,它工作得很好:
var sortedResults = dic.OrderByDescending(ex1.Compile()).ThenByDescending(ex2.Compile()).ThenByDescending(ex3.Compile());
但是,由于排序表达式的数量在运行时会有所不同,所以我需要动态地构建这个表达式,这正是我努力的地方。
我知道可以在运行时使用MethodCallExpression构建查询表达式。MSDN示例显示如下:
// ***** OrderBy(company => company) *****
// Create an expression tree that represents the expression
// 'whereCallExpression.OrderBy(company => company)'
MethodCallExpression orderByCallExpression = Expression.Call(
typeof(Queryable),
"OrderBy",
new Type[] { queryableData.ElementType, queryableData.ElementType },
whereCallExpression,
Expression.Lambda<Func<string, string>>(pe, new ParameterExpression[] { pe }));
// ***** End OrderBy *****
但是,我无法从这个示例过渡到使用以下内容的词典:
Func<KeyValuePair<string, Dictionary<int, int>>, int>
我想我需要做的是这样写(这是部分psuedo代码):
private static void Test()
{
var query = data.AsQueryable()
foreach (int key in ListOfRequiredKeys)
{
Expression<Func<KeyValuePair<string, Dictionary<int, int>>, int>> exp = (r => r.Value[key]);
MakeQuery(exp, query);
}
}
private static IQueryable MakeQuery(Expression<Func<KeyValuePair<string, Dictionary<int, int>> exp, IQueryable query)
{
MethodCallExpression orderByCallExpression = Expression.Call(
typeof(Queryable),
"ThenBy",
new Type[] { query.ElementType, query.ElementType },
query.Expression,
Expression.Lambda<Expression<Func<KeyValuePair<string, Dictionary<int, int>>>(exp));
}
我知道这不是正确的语法,但它应该表明我的想法。有人能建议如何从msdn示例转移到动态地对字典进行排序吗?
谢谢
杰森
最佳答案
你可以写
var result = data.OrderByDescending(someValue)
.ThenByDescending(someothervalue)
.ThenByDescending(anothervalue); //...etc
作为
var result = data.OrderByDescending(someValue);
result = result.ThenByDescending(someothervalue);
result = result.ThenByDescending(anothervalue);
//...etc
所以你只需要调用
OrderBy(Descending)
就可以得到一个IOrderedEnumerable/Queryable
,然后可以在上面重复调用ThenBy(Descending)
。private static void Test()
{
var query = data.AsQueryable();
var f = ListOfRequiredKeys.First();
var orderedQuery = query.OrderBy(r => r.Value[f]);
foreach (int key in ListOfRequiredKeys.Skip(1))
{
var k = key;
orderedQuery = orderedQuery.ThenBy(r => r.Value[k]);
}
}