简体   繁体   English

构建表达式树以在LINQ中动态排序字典字典

[英]Building expression tree to dynamically sort a dictionary of dictionaries in LINQ

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. 我正在努力构建我的表达式树的MethodCallExpression

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. 在运行时确定'ThenBy'或'ThenByDescending'子句的数量。

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: 让我们说一个例子需要按键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]);

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. 我知道可以使用MethodCallExpression在运行时构建查询表达式。 The MSDN example shows this: 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 *****

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? 有人可以建议如何从MSDN示例移动到动态排序这个字典词典?

Thanks 谢谢
Jason 贾森

You can write 你可以写

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

as

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

So you just need to call OrderBy(Descending) to get an IOrderedEnumerable/Queryable and can then repeated call ThenBy(Descending) on it. 因此,您只需要调用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]);
    }        
}   

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM