我想嵌入一个表达式树,例如
Expression<Func<MyObject, double>> expr = (o) => o.Value;
到解析器生成的更大的表达式树中。但是,参数o已在外部表达式树中定义。原则上,我必须搜索expr
的主体,并用解析后的表达式树中的实例替换参数的所有出现。
有没有内置的方法来做到这一点? 或者甚至有一种方法可以在预先指定参数的实例时直接生成lambda表达式吗?
答案 0 :(得分:2)
您无法直接指示编译器重用现有的ParameterExpression
实例,但您可以在之后替换它们(实际上是创建新的表达式树)。
内置ExpressionVisitor
对繁重的工作有很大的帮助;它是您从中添加所需功能的无操作访问者。在这种情况下,您需要指示它替换ParameterExpression
个实例,这样您就可以拥有:
// Sorry for the atrocious formatting, wanted to keep it scrollbar-free
class ParameterReplacementVisitor : ExpressionVisitor
{
private readonly
IEnumerable<KeyValuePair<ParameterExpression, ParameterExpression>>
replacementMap;
public ParameterReplacementVisitor(
IEnumerable<KeyValuePair<ParameterExpression, ParameterExpression>> map)
{
this.replacementMap = map;
}
protected override Expression VisitLambda<T>(Expression<T> node)
{
return Expression.Lambda<T>(
Visit(node.Body),
node.Parameters.Select(Visit).Cast<ParameterExpression>());
}
protected override Expression VisitParameter(ParameterExpression node)
{
var replacement = this.replacementMap
.Where(p => p.Key == node)
.DefaultIfEmpty()
.First().Value;
return base.VisitParameter(replacement ?? node);
}
}
你可以这样使用:
Expression<Func<int, bool>> e1 = i => true;
Expression<Func<int, bool>> e2 = j => false;
Console.WriteLine(e1.Parameters[0] == e2.Parameters[0]); // false
var replacements = new Dictionary<ParameterExpression, ParameterExpression>
{
{ e1.Parameters[0], e2.Parameters[0] }
};
var replacer = new ParameterReplacementVisitor(replacements);
var e3 = replacer.VisitAndConvert(e1, "replacing parameters");
Console.WriteLine(e3.Parameters[0] == e2.Parameters[0]); // true