简体   繁体   English

如何将多个Linq表达式的结果合并为一个表达式?

[英]How to combine result of multiple Linq Expressions into one Expression?

I have a list of Linq Expressions List<Expression> where each expression type (the type the expression would return) is either Item or Item[] . 我有一个Linq Expressions List<Expression>列表,其中每个表达式类型(表达式将返回的类型)是ItemItem[]

I'm trying to write some code that would take mentioned collection as an input parameter and produce a Linq Expression that would return one list (or array) of items ( Item[] ). 我正在尝试编写一些代码,这些代码将提到的collection作为输入参数,并生成一个Linq表达式,该表达式将返回项的一个列表(或数组)( Item[] )。

Here is an abstract example: 这是一个抽象的例子:

public static string[] GetStrings()
{
    return new[]
        {
            "first",
            "second",
            "third"
        };
}

public static string GetString()
{
    return "single1";
}

private void SOExample()
{
    var expressions = new List<Expression>
    {
        Expression.Call(GetType().GetMethod("GetString")),
        Expression.Call(GetType().GetMethod("GetStrings")), 
        Expression.Call(GetType().GetMethod("GetString")),
        Expression.Call(GetType().GetMethod("GetStrings"))
    };

    // some magic code here
    var combined = SomeMagicHere(expressions);
}


private Expression SomeMagicHere(List<Expression> expressions)
{
    foreach (var expression in expressions)
    {
        if (expression.Type.IsArray)
        {
            // Use array's elements
        } 
        else
        {
            // Use expression
        }
    }

What I'm trying to make is to produce one Expression that would return a list of Item (strings in my example) from provided list. 我想做的是生成一个表达式,该表达式将从提供的列表中返回一个Item列表(在我的示例中为字符串)。

This seems a very odd scenario, and in most cases I would expect to see use of raw reflection (or maybe delegates) rather than Expression here - it isn't an obvious fit. 这似乎是一个非常奇怪的情况,在大多数情况下,我希望看到此处使用原始反射(或委托)而不是Expression这显然不是合适的。 But: you can do that by turning the expressions into a block that each call Add or AddRange to append values into the list. 但是:您可以通过将表达式变成一个块来实现 ,每个调用AddAddRange将值追加到列表中。 For example: 例如:

using System;
using System.Collections.Generic;
using System.Linq.Expressions;

static class Program
{
    public static string GetString()
    {
        return "single1";
    }
    public static string[] GetStrings()
    {
        return new[]
        {
            "first",
            "second",
            "third"
        };
    }
    static void Main()
    {
        var expressions = new List<Expression>
        {
            Expression.Call(typeof(Program).GetMethod("GetString")),
            Expression.Call(typeof(Program).GetMethod("GetStrings")), 
            Expression.Call(typeof(Program).GetMethod("GetString")),
            Expression.Call(typeof(Program).GetMethod("GetStrings"))
        };

        // some magic code here
        var combined = SomeMagicHere(expressions);

        // show it works
        var lambda = Expression.Lambda<Func<List<string>>>(combined);
        var list = lambda.Compile()();
    }
    private static Expression SomeMagicHere(List<Expression> expressions)
    {
        List<Expression> blockContents = new List<Expression>();
        var var = Expression.Variable(typeof(List<string>), "list");
        blockContents.Add(Expression.Assign(var,
            Expression.New(typeof(List<string>))));
        foreach (var expression in expressions)
        {
            if (expression.Type.IsArray)
            {
                blockContents.Add(Expression.Call(
                    var, var.Type.GetMethod("AddRange"), expression));
            }
            else
            {
                blockContents.Add(Expression.Call(var,
                    var.Type.GetMethod("Add"), expression));
            }
        }
        blockContents.Add(var); // last statement in a block is the effective
                                // value of the block
        return Expression.Block(new[] {var}, blockContents);
    }

}

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

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