C# 用复杂表达式替换表达式树中的参数值

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

我使用以下方法将ParameterExpression替换为另一个:

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(_参数)应该是最理想的方式。