0

I have a method that is used to generate a NewExpression.

public NewExpression CreateNewExpression( Expression<Func<T>> expression )
{
    return expression.Body as NewExpression;
}

You can then do stuff like this.

CreateNewExpression( () => new MyType() );

This is later on used to create a delegate the can be executed to create an object.

var body = Expression.MemberInit( constructorExpression, bindings );
var funcType = typeof( Func<> ).MakeGenericType( objectType );
var lambda = Expression.Lambda( funcType, body ).Compile();

This works great, but now I would like to pass some data into the method so it can be used in the construction of the object.

public NewExpression CreateNewExpression( Expression<Func<T, Data>> expression )

This would then be used like this.

CreateNewExpression( data => new MyType( data.Id ) );

I can't for the life of me figure out how to create the proper expression to pass the data in for the constructor to use.

If I don't extract the body from the expression in CreateNewExpression and do Expression.Invoke, I don't know how to set the properties to it after.

If I extract the body, I can set the properties using Expression.MemberInit, but then I can't figure out how to pass the data to it.

How can I do this?

4
  • Can you elaborate a bit more on your goals? I see no sense on using Expressiont trees here, you pass in a delegate, and it does what you want, no? Commented Apr 4, 2016 at 21:40
  • I'm trying to boil it down to the basics. It's being used to create class objects on the fly via a mapping file. Commented Apr 4, 2016 at 21:54
  • Taking an expression just to take the body out, and then reconstruct it and compile does not seem to me as something useful. In addition in your case when you try to use a parameter, by just taking the body you lose the reference to the param. Can you post the intended API that you want to have? or at least an example usage of this? With some example classes plz Commented Apr 4, 2016 at 22:00
  • It's used in this library. If you have a better way to do it, I'd love to know. github.com/JoshClose/CsvHelper/tree/master/src/CsvHelper Commented Apr 5, 2016 at 1:26

2 Answers 2

2

When you want to use an expression that contains ParameterExpression, you need to reuse that same ParameterExpression in the final expression too.

To do this, you can access the Parameters of the original expression and then pass the parameter to Expression.Lambda(). The result could look something like this:

public Delegate M<T>(Expression<Func<Data, T>> expression)
{
    var objectType = typeof(T);

    var constructorExpression = (NewExpression)expression.Body;
    var constructorParameterExpression = expression.Parameters.Single();

    var bindings = …;

    var body = Expression.MemberInit( constructorExpression, bindings );
    var funcType = typeof( Func<,> ).MakeGenericType( typeof(Data), objectType );
    var lambda = Expression.Lambda( funcType, body, constructorParameterExpression )
        .Compile();

    return lambda;
}
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks so much! I had exactly this but didn't pass the original constructor parameter expression. I tried creating a new one. This works great.
0

I think what could be the answer to your problem is Expression.Parameter.

I found a blog entry on geeks with blogs which utilizes this. The only downside of this solution is that you'd have to create new overloads for when you need more than three arguments. But I guess this could be easily solved with params object[].

Comments

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.