Expression to create an instance with object initializer

后端 未结 2 1394
闹比i
闹比i 2020-12-25 15:09

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:

/         


        
相关标签:
2条回答
  • 2020-12-25 15:16

    Finally I found my answer:

    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(local, "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), 
            /* I forgot to remove this line:
             * Expression.Return(Expression.Label(expectedType), local, expectedType), 
             * and now it works.
             * */
            returnExpression, 
            returnLabel 
            ); 
        Creator = 
            Expression.Lambda<Func<bool, dynamic>>(block, displayValueParam) 
                .Compile(); 
    }
    

    UPDATE:

    While it works fine, but @svick provide a better and shorter way in his answer that is actuallt wath I was looking for: MemberInit. Please see @svick's answer.

    0 讨论(0)
  • 2020-12-25 15:22

    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}
    
    0 讨论(0)
提交回复
热议问题