给定两个“选择器”表达式,您必须从它们中获取绑定MemberInitExpression
并使用所有绑定创建一个新表达式。但是这个表达式是行不通的,因为它对一个参数使用了两个不同的参数表达式。我们也需要解决这个问题。
鉴于...
Expression<Func<TSource, TResult>> left = ... // columns
Expression<Func<TSource, TResult>> right = ... // more columns
...拿起绑定...
var leftInit = left.Body as MemberInitExpression;
var rightInit = right.Body as MemberInitExpression;
var bindings = leftInit.Bindings.Concat(rightInit.Bindings);
...创建一个新表达式...
var result = Expression.Lambda<Func<TSource, TResult>>(
Expression.MemberInit(Expression.New(typeof(TResult)), bindings), ???);
...但是,需要单个参数...
var binder = new ParameterBinder(left.Parameters[0], right.Parameters[0]);
var bindings = binder.Visit(leftInit.Bindings.Concat(rightInit.Bindings));
// now, just use right.Parameters[0] as parameter...
而且,使用表达式访问者替换参数效果很好:
class ParameterBinder : ExpressionVisitor
{
readonly ParameterExpression parameter;
readonly Expression replacement;
public ParameterBinder(ParameterExpression parameter, Expression replacement)
{
this.parameter = parameter;
this.replacement = replacement;
}
protected override Expression VisitParameter(ParameterExpression node)
{
if (node == parameter)
return replacement;
return base.VisitParameter(node);
}
}
抽象这些管道的东西效果很好。事实上,你可以只使用一个现有的库(剧透:我是作者),这应该会导致这样的事情:
var merged = columns.Apply(moreColumns);