【问题标题】:c# expressions combine property expression with lambda expressionc#表达式将属性表达式与lambda表达式结合起来
【发布时间】:2014-03-18 13:57:28
【问题描述】:

请帮助解决以下问题:

public class TestParent
{
    public int Number { get; set; }
}

public class Test
{
    public TestParent Parent { get; set; }
}

class Program
{
    static void Main(string[] args)
    {
        Expression<Func<TestParent, bool>> parentExpression = x => x.Number == 10;
        Expression<Func<Test, TestParent>> testExpression = x => x.Parent;

        var test = new Test {Parent = new TestParent {Number = 10}};

        Expression<Func<Test, bool>> composedExpression = ?; // x => x.Parent.Number == 10

        bool result = composedExpression.Compile()(test);

        if (result)
        {
            Console.WriteLine("Test passed!");
        }
    }
}

【问题讨论】:

  • 请提供更多关于您想要完成的任务的详细信息。

标签: c# lambda expression


【解决方案1】:

我们可以为这样的表达式创建一个Compose 方法:

public static Expression<Func<TFirstParam, TResult>>
    Compose<TFirstParam, TIntermediate, TResult>(
    this Expression<Func<TFirstParam, TIntermediate>> first,
    Expression<Func<TIntermediate, TResult>> second)
{
    var param = Expression.Parameter(typeof(TFirstParam), "param");

    var newFirst = first.Body.Replace(first.Parameters[0], param);
    var newSecond = second.Body.Replace(second.Parameters[0], newFirst);

    return Expression.Lambda<Func<TFirstParam, TResult>>(newSecond, param);
}

这是使用以下辅助方法将一个表达式的所有实例替换为另一个:

public static Expression Replace(this Expression expression,
    Expression searchEx, Expression replaceEx)
{
    return new ReplaceVisitor(searchEx, replaceEx).Visit(expression);
}

internal class ReplaceVisitor : ExpressionVisitor
{
    private readonly Expression from, to;
    public ReplaceVisitor(Expression from, Expression to)
    {
        this.from = from;
        this.to = to;
    }
    public override Expression Visit(Expression node)
    {
        return node == from ? to : base.Visit(node);
    }
}

这允许你写:

Expression<Func<Test, bool>> composedExpression = 
    testExpression.Compose(parentExpression);

【讨论】:

    【解决方案2】:

    我认为您正在尝试创建一个新表达式,该表达式包含现在在两个单独的表达式 parentExpressiontestExpression 中定义的逻辑。

    不幸的是,您不能像那样轻松地组合表达式(不分解表达式并使用内部表达式主体),因为表达式的参数不同,您必须手动从两个表达式的内容创建表达式。您不能按原样使用这两个表达式,并将它们组合起来。

    您可以编译这两个表达式,并在新表达式中使用它们。会是这样的。但请注意,composedExpression 只不过是对已编译表达式的调用。它将包含现在在其他两个表达式中定义的逻辑。

    Expression<Func<TestParent, bool>> parentExpression = x => x.Number == 10;
    Expression<Func<Test, TestParent>> testExpression = x => x.Parent;
    
    var parentExpressionCompiled = parentExpression.Compile();
    var testExpressionCompiled = testExpression.Compile();
    
    var test = new Test {Parent = new TestParent {Number = 10}};
    
    Expression<Func<Test, bool>> composedExpression = x => parentExpressionCompiled(testExpressionCompiled(x));
    
    bool result = composedExpression.Compile()(test);
    
    if (result) {
        Console.WriteLine("Test passed!");
    }
    

    【讨论】:

    • 这在几乎所有使用Expression 对象的情况下作为解决方案基本上是无用的。从已编译的表达式中创建表达式几乎可以肯定不是任何东西都可以使用的。
    【解决方案3】:

    完成这个:

    var composedExpression = testExpression.Combine(parentExpression, true);
    

    Combine 实现的来源:Combining two lambda expressions in c#

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-10-05
      • 1970-01-01
      • 1970-01-01
      • 2020-07-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多