c#表达式将属性表达式与lambda表达式结合起来

时间:2014-03-18 13:57:28

标签: c# lambda expression

请帮助解决以下问题:

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

3 个答案:

答案 0 :(得分:3)

我们可以为这样的表达式创建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);

答案 1 :(得分:0)

我认为您正在尝试创建一个新表达式,该表达式包含现在在两个单独的表达式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!");
}

答案 2 :(得分:0)

完成这项工作:

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

其中Combine实施来自:Combining two lambda expressions in c#