System.Linq.Expressions:在运行时绑定LambdaExpression输入

时间:2013-01-10 00:02:44

标签: c# .net

考虑以下设置:

class A { public int x; }
class B { public int y; }

static class Helper
{
    public static Expression<Func<B>> BindInput(
        Expression<Func<A, B>> expression,
        A input)
    {
        //TODO
    }
}

static void Main(string[] args)
{
    Expression<Func<B>> e = Helper.BindInput(
        (A a) => new B { y = a.x + 3 },
        new A { x = 4 });

    Func<B> f = e.Compile();
    Debug.Assert(f().y == 7);
}

我想在方法BindInput中做的是将表达式转换为嵌入input。在Main中的示例用法中,生成的表达式e将为

() => new B { y = input.x + 3 }

其中input是传递给BindInput的第二个值。

我将如何做到这一点?

修改

我应该补充一下,以下表达式e 我正在寻找的内容:

((A a) => new B { y = a.x + 3 })(input)

获得这一点非常简单,因为它只涉及在现有表达式之上添加一个图层。

1 个答案:

答案 0 :(得分:4)

经过大量搜索,我偶然发现了神奇的ExpressionVisitor课程。以下似乎完美地运作:

class MyExpressionVisitor : ExpressionVisitor
{
    public ParameterExpression TargetParameterExpression { get; private set; }
    public object TargetParameterValue { get; private set; }
    public MyExpressionVisitor(ParameterExpression targetParameterExpression, object targetParameterValue)
    {
        this.TargetParameterExpression = targetParameterExpression;
        this.TargetParameterValue = targetParameterValue;
    }
    protected override Expression VisitParameter(ParameterExpression node)
    {
        if (node == TargetParameterExpression)
            return Expression.Constant(TargetParameterValue);
        return base.VisitParameter(node);
    }
}

static class Helper
{
    public static Expression<Func<B>> BindInput(Expression<Func<A, B>> expression, A input)
    {
        var parameter = expression.Parameters.Single();
        var visitor = new MyExpressionVisitor(parameter, input);
        return Expression.Lambda<Func<B>>(visitor.Visit(expression.Body));
    }
}