【问题标题】:How to combine result of multiple Linq Expressions into one Expression?如何将多个 Linq 表达式的结果组合成一个表达式?
【发布时间】:2012-10-08 10:36:33
【问题描述】:

我有一个 Linq 表达式列表 List<Expression>,其中每个表达式类型(表达式将返回的类型)是 ItemItem[]

我正在尝试编写一些代码,将提到的集合作为输入参数并生成一个 Linq 表达式,该表达式将返回一个项目列表(或数组) (Item[])。

这是一个抽象的例子:

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
        }
    }

我要做的是生成一个表达式,该表达式将从提供的列表中返回Item(在我的示例中为字符串)列表。

【问题讨论】:

  • 表达式本身很少使用,当不是LambdaExpression 的一部分时更不用说。是否有特定原因使用Expression 而不是......好吧,也许只是反射,也许是代表等。Expression 在这里感觉不是一个明显的选择。另外:您在结果中寻找什么:您是否希望它评估方法,结合它们的结果?或者构建一个Expression,它会在编译等时评估树?要么...?基本上:你的理想结果会是什么样子?另外:目标调用者是什么? (重要的是:ORM 调用者不会喜欢这样)

标签: c# linq lambda expression linq-expressions


【解决方案1】:

这似乎是一个非常奇怪的场景,在大多数情况下,我希望在这里看到使用原始反射(或者可能是委托)而不是 Expression - 这不是一个明显的适合。但是:您可以通过将表达式转换为 block 来实现,每个调用 AddAddRange 将值附加到列表中。例如:

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);
    }

}

【讨论】:

  • 嗨,Marc,感谢您的回复 - 这正是我想要的。我创建这个表达式作为最终被编译和执行的更大表达式的一部分。该代码在自定义语言编译器中使用:)
  • @Hubert 我一定是疯了,但是当我需要的时候,我就直接在ILGenerator 上做;p
  • 使用 Linq 表达式的想法不是我的,我必须按照我的发现(ANTLR + Linq 表达式):) 无论如何非常感谢,我觉得我必须更多地了解 Linq 表达式:)
猜你喜欢
  • 2013-03-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多