Hi All,
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