1

I'm replacing a ParameterExpression with another with the following method:

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;
  }
}

I'm using it like this:

  ParameterExpression value = Expression.Parameter( ..., "value" );

  return Expression.Block
  (
       new[] { value },

        Expression.Assign( value, valueGetter ),

        SomeLambdaExpression.Body.ReplaceParameter( value, 
            SomeLambdaExpression.Body.Parameters[0].Name);
  )

As you see in order to replace the parameter at the moment I need to declare and assign a new, temporary, ParameterExpression.

I was wondering if there's a way to avoid that work and replace a ParameterExpression directly with the Expression providing the value (valueGetter).

somethig like this to be clear:

 return SomeLambdaExpression.Body.ReplaceParameter( valueGetter, 
     SomeLambdaExpression.Body.Parameters[0].Name);
6
  • 1
    you should replace parameters by instance, not by name and type, that might result in errors!! Drop the name, and use the parameter from the expression provided. Example: stackoverflow.com/questions/29448432/… MultiParamReplaceVisitor Commented May 26, 2017 at 14:54
  • @MBoros completely false! what would you do if you had two params of the same type? you surely need the name to identify which one you wanna replace! Commented May 26, 2017 at 15:41
  • 1
    that is why you replace by INSTANCE (not type). The name has no meaning. In list => list.Where(x => x > 4).Select(x => x + 1) you have 2 DIFFERENT parameters, both of type int, and name x. this is one expression tree. You can manually construct trees where all parameters are called the same, and internal ones can have the same name and type as the external ones. You have to go by INSTANCE. Commented May 27, 2017 at 11:25
  • Ah, ok i got what you mean. In my case parameter instances are lost along the way of building complex expressions. I don't hold references to any ParameterExpression instance so in order to replace them I perform a replacement on each scope knowing you can't declare a varibale with the same name in the same scope. Take a look at my project on github: UltraMapper. Commented May 29, 2017 at 7:49
  • Well, from my experience that is a very bad practice, and can lead to serious headache. If you have the body of a lambdaexpression, then an inner scope might define a parameter with the same name/type. Then inside the inner scope you will still need instance comparison. E.g Exp<Func<int, bool>> pred = x => x > 3; var ints = new List<int>(); Exp<Func<int, bool>> pred2 = x => ints.AsQueryable(pred); Imagine someone managed to actually quote pred inside pred2 (not just a field access on a closure), which is not so hard. if you only have pred2.Body in hand, how do you know which x is in x>3? Commented May 31, 2017 at 6:47

1 Answer 1

1

In your visitor, instead of return base.VisitParameter( _parameter );, you can do just return _expression;.

Sign up to request clarification or add additional context in comments.

1 Comment

Though I suggest return base.VisitParameter( _parameter ); should be the most ideal way.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.