另一个解决方案是使用
ExpressionVisitor
,将右表达式中的参数替换为整个左表达式,换句话说,将左表达式嵌入到右表达式中。
ExpressionVisitor
非常简单,只需向构造函数添加所需的数据,重写一个方法即可。
internal sealed class ParameterReplaceVisitor : ExpressionVisitor
{
private readonly ParameterExpression _searched;
private readonly Expression _replaced;
public ParameterReplaceVisitor(ParameterExpression searched, Expression replaced)
{
if (searched == null)
throw new ArgumentNullException(nameof(searched));
if (replaced == null)
throw new ArgumentNullException(nameof(replaced));
_searched = searched;
_replaced = replaced;
}
protected override Expression VisitParameter(ParameterExpression node)
{
if (node == _searched)
return _replaced;
return base.VisitParameter(node);
}
}
它可以很容易地扩展以处理构造函数中的表达式集合,但我将其保持简短。
现在,您只需要在表达式体上使用它并构建新的lambda即可。
private static Expression<Func<TIn, TOut>> Merge<TIn, TInter, TOut>(Expression<Func<TIn, TInter>> left, Expression<Func<TInter, TOut>> right)
{
var merged = new ParameterReplaceVisitor(right.Parameters[0], left.Body).Visit(right.Body);
var lambda = Expression.Lambda<Func<TIn, TOut>>(merged, left.Parameters[0]);
return lambda;
}
我在这段代码上进行了测试:
Expression<Func<string, int>> l = s => s.Length + 5;
Expression<Func<int, string>> r = i => i.ToString() + " something";
var merged = Merge(l, r);
var res = merged.Compile()("test");
结果如预期所示:9 something
。
编辑:
如果性能是您关心的问题,为什么要使用表达式而不是普通的Func
?然后您可以一个接一个地调用它们。这些表达式树是否稍后被分析?