Building an expression tree for dynamically sorting a dictionary of dictionaries in LINQ

I am trying to dynamically create an expression tree to change the sort order for the data contained in a dictionary of dictionaries. There is a lot of information about dynamically defining a column for sorting, but this is actually not the part that I'm having problems with. I am struggling with a MethodCallExpression that builds my expression tree.

In this example, I have simplified the dictionary:

Dictionary<string, Dictionary<int, int>> data = new Dictionary<string, Dictionary<int, int>>(); 

I am trying to create an expression that would be equivalent to something like this:

 data.OrderByDescending(someValue) .ThenByDescending(someothervalue) .ThenByDescending(anothervalue)...etc 

Where the number of ThenBy or ThenByDescending offers at runtime is indicated.

Let's say that one example needs to be sorted by the keys 4, then 3, then 1. I have established (I think) that the following expressions translate into 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 change at runtime, I need to build this dynamically, which I'm afraid of. I know that query expressions can be created at runtime using the MethodCallExpression method. An 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 a dictionary of dictionaries that uses this:

 Func<KeyValuePair<string, Dictionary<int, int>>, int> 

It seems to me that I need to 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 this is not the correct syntax, but it should indicate my thinking. Can anyone advise how to switch from the MSDN example, dynamically sort this dictionary of dictionaries?

thanks
Jason

+4
source share
1 answer

You can write

 var result = data.OrderByDescending(someValue) .ThenByDescending(someothervalue) .ThenByDescending(anothervalue); //...etc 

a

 var result = data.OrderByDescending(someValue); result = result.ThenByDescending(someothervalue); result = result.ThenByDescending(anothervalue); //...etc 

So you just need to call OrderBy(Descending) to get IOrderedEnumerable/Queryable , and then repeat the call to ThenBy(Descending) on it.

 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]); } } 
+4
source

All Articles