我正在尝试动态构建表达式树,以便我可以更改字典字典中包含的数据的排序顺序。有很多关于动态指定要排序的列的信息,但这并不是我遇到问题的部分。我正在努力构建我的表达式树的 MethodCallExpression 。
出于这个例子的目的,我简化了字典:
Dictionary<string, Dictionary<int, int>> data = new Dictionary<string, Dictionary<int, int>>();
我正在尝试构建一个类似于以下内容的表达式:
data.OrderByDescending(someValue)
.ThenByDescending(someothervalue)
.ThenByDescending(anothervalue)...etc
在运行时确定'ThenBy'或'ThenByDescending'子句的数量。
让我们说一个例子需要按键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>
我认为我需要做的是写这样的东西(这是部分伪代码):
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示例移动到动态排序这个字典词典吗?
感谢
杰森
答案 0 :(得分:4)
你可以写
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]);
}
}