Search code examples
c#dynamiclambdaexpressionexpression-trees

Expression to create an instance with object initializer


Is there any way to create an instance of an object with object initializer with an Expression Tree? I mean create an Expression Tree to build this lambda:

// my class
public class MyObject {
    public bool DisplayValue { get; set; }
}

// my lambda:
var lambda = (Func<bool, MyObject>)
             (displayValue => new MyObject { DisplayValue = displayValue });

How can I create this lambda with an Expression Tree?

UPDATE:

I tryed myself and write following code:

    public static Func<bool, dynamic> Creator;

    static void BuildLambda() {
        var expectedType = typeof(MyObject);
        var displayValueParam = Expression.Parameter(typeof(bool), "displayValue");
        var ctor = Expression.New(expectedType);
        var local = Expression.Parameter(expectedType, "obj");
        var displayValueProperty = Expression.Property(ctor, "DisplayValue");

        var returnTarget = Expression.Label(expectedType);
        var returnExpression = Expression.Return(returnTarget,local, expectedType);
        var returnLabel = Expression.Label(returnTarget, Expression.Default(expectedType));

        var block = Expression.Block(
            new[] { local },
            Expression.Assign(local, ctor),
            Expression.Assign(displayValueProperty, displayValueParam),
            Expression.Return(Expression.Label(expectedType), local, expectedType),
            returnExpression,
            returnLabel
            );
        Creator =
            Expression.Lambda<Func<bool, dynamic>>(block, displayValueParam)
                .Compile();
    }

But it throws the following error:

Cannot jump to undefined label ''.

Can everybody help me please?


Solution

  • To represent object initializers in an Expression, you should use Expression.MemberInit():

    Expression<Func<bool, MyObject>> BuildLambda() { 
        var createdType = typeof(MyObject);
        var displayValueParam = Expression.Parameter(typeof(bool), "displayValue"); 
        var ctor = Expression.New(createdType);
        var displayValueProperty = createdType.GetProperty("DisplayValue");
        var displayValueAssignment = Expression.Bind(
            displayValueProperty, displayValueParam);
        var memberInit = Expression.MemberInit(ctor, displayValueAssignment);
    
        return
            Expression.Lambda<Func<bool, MyObject>>(memberInit, displayValueParam);
    }
    

    To verify this actually does what you want, you can call ToString() on the created expression. In this case, the output is as expected:

    displayValue => new MyObject() {DisplayValue = displayValue}