C# 用复杂表达式替换表达式树中的参数值
我使用以下方法将ParameterExpression替换为另一个:C# 用复杂表达式替换表达式树中的参数值,c#,expression-trees,expressionvisitor,C#,Expression Trees,Expressionvisitor,我使用以下方法将ParameterExpression替换为另一个: public static Expression ReplaceParameter( this Expression expression, ParameterExpression parameter, string name ) { return new ExpressionParameterReplacer( parameter, name ).Visit( expression ); } inter
public static Expression ReplaceParameter( this Expression expression,
ParameterExpression parameter, string name )
{
return new ExpressionParameterReplacer( parameter, name ).Visit( expression );
}
internal class ExpressionParameterReplacer : ExpressionVisitor
{
private readonly ParameterExpression _parameter;
private readonly string _name;
protected override Expression VisitParameter( ParameterExpression node )
{
if( node.Name == _name && (node.Type == _parameter.Type ||
node.Type.IsAssignableFrom( _parameter.Type )) )
{
return base.VisitParameter( _parameter );
}
return base.VisitParameter( node );
}
internal ExpressionParameterReplacer( ParameterExpression parameter, string name )
{
_parameter = parameter;
_name = name;
}
}
我是这样使用它的:
ParameterExpression value = Expression.Parameter( ..., "value" );
return Expression.Block
(
new[] { value },
Expression.Assign( value, valueGetter ),
SomeLambdaExpression.Body.ReplaceParameter( value,
SomeLambdaExpression.Body.Parameters[0].Name);
)
正如您所看到的,为了在此时替换参数,我需要声明并分配一个新的、临时的ParameterExpression
我想知道是否有办法避免这种工作,直接用提供值的表达式(valueGetter
)替换ParameterExpression
像这样的事情很清楚:
return SomeLambdaExpression.Body.ReplaceParameter( valueGetter,
SomeLambdaExpression.Body.Parameters[0].Name);
在访问者中,而不是
返回base.VisitParameter(_参数)
,只需执行return\u表达式代码>您应该按实例替换参数,而不是按名称和类型,这可能会导致错误!!删除名称,并使用所提供表达式中的参数。例子:MultiParamReplaceVisitor@MBoros完全错误!如果有两个相同类型的参数,您会怎么做?你肯定需要这个名字来确定你想换哪一个!这就是为什么要替换为实例(而不是类型)。这个名字没有任何意义。在list=>list.Where(x=>x>4)中选择(x=>x+1)您有两个不同的参数,类型都是int,名称都是x。这是一个表达式树。您可以手动构造树,其中所有参数的调用相同,并且内部参数可以与外部参数具有相同的名称和类型。你得举个例子。啊,好吧,我明白你的意思了。在我的例子中,参数实例在构建复杂表达式的过程中丢失。我不保留对任何ParameterExpression实例的引用,因此为了替换它们,我在每个作用域上执行替换,因为我知道不能在同一作用域中声明具有相同名称的变量。看看我在github上的项目:UltraMapper。根据我的经验,这是一个非常糟糕的做法,可能会导致严重的头痛。如果具有lambdaexpression的主体,则内部作用域可能会定义具有相同名称/类型的参数。然后在内部范围内,仍然需要进行实例比较。例如Exp pred=x=>x>3;var ints=新列表();Exp pred2=x=>ints.AsQueryable(pred);想象一下,有人设法在pred2中引用pred(而不仅仅是闭包上的字段访问),这并不难。如果您手头只有pred2.Body,那么如何知道x>3中的哪个x?尽管我建议返回base.VisitParameter(_参数)代码>应该是最理想的方式。