System.Linq.Expressions:在运行时绑定LambdaExpression输入
请考虑以下设置:
class A { public int x; } class B { public int y; } static class Helper { public static Expression<Func> BindInput( Expression<Func> expression, A input) { //TODO } } static void Main(string[] args) { Expression<Func> e = Helper.BindInput( (A a) => new B { y = ax + 3 }, new A { x = 4 }); Func f = e.Compile(); Debug.Assert(f().y == 7); }
我想在BindInput
方法中BindInput
是将表达式转换为嵌入到其中的input
。 在Main
的示例用法中,结果表达式e
将是
() => new B { y = input.x + 3 }
其中input
是传递给BindInput
的第二个值。
我该怎么做呢?
编辑:
我应该补充说下面的表达式e
不是我想要的:
((A a) => new B { y = ax + 3 })(input)
这将获得相当简单,因为它只涉及在现有表达式之上添加一个层。
经过大量的搜索,我偶然发现了神奇的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> BindInput(Expression> expression, A input) { var parameter = expression.Parameters.Single(); var visitor = new MyExpressionVisitor(parameter, input); return Expression.Lambda>(visitor.Visit(expression.Body)); } }