构建表达式树以动态排序 LINQ 中的字典字典
我正在尝试动态构建表达式树,以便可以更改字典字典中包含的数据的排序顺序。有很多关于动态指定排序依据的列的信息,但这并不是我真正遇到问题的部分。我正在与构建表达式树的 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 示例转移到动态对这本字典的字典进行排序吗?
谢谢
贾森
I am attempting to dynamically build up an expression tree so that I can change the sort order for data contained in a dictionary of dictionaries. There is lots of information about dynamically specifying the column to sort by, but this is not really the part I am having problems with. I am struggling with the MethodCallExpression that builds my expression tree.
For purposes of this example, I've simplified the dictionary:
Dictionary<string, Dictionary<int, int>> data = new Dictionary<string, Dictionary<int, int>>();
I'm trying to build up an expression that would be the equivilent of something like this:
data.OrderByDescending(someValue)
.ThenByDescending(someothervalue)
.ThenByDescending(anothervalue)...etc
Where the number of 'ThenBy' or 'ThenByDescending' clauses is determined at runtime.
Lets say one example needed to sort by the keys 4, then 3, then 1. I've established (I think) that the following expressions translate to my 3 sort orders:
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]);
So at compile time I can write this expression and it works fine:
var sortedResults = dic.OrderByDescending(ex1.Compile()).ThenByDescending(ex2.Compile()).ThenByDescending(ex3.Compile());
However since the number of sort expressions will vary at runtime I need to build this dynamically, which is where I am struggling.
I am aware that query expressions can be built up at runtime using MethodCallExpression. The MSDN example shows this:
// ***** 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 *****
However, I just can't make the transition from this example, to my dictionary of dictionaries that uses this:
Func<KeyValuePair<string, Dictionary<int, int>>, int>
What I think I need to do is write something like this (this is in partial psuedo code):
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));
}
I know that isn't the correct syntax, but it should indicate my thinking. Can some one advise how to move from the MSDN example, to dynamically sort this dictionary of dictionaries?
Thanks
Jason
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您可以编写
为
因此,您只需要调用
OrderBy(Descending)
即可获取IOrderedEnumerable/Queryable
,然后可以重复调用ThenBy(Descending)
在它上面。You can write
as
So you just need to call
OrderBy(Descending)
to get anIOrderedEnumerable/Queryable
and can then repeated callThenBy(Descending)
on it.