Expression pour créer une instance avec un initialiseur d'objet

c# dynamic expression expression-trees lambda

Question

Est-il possible de créer une instance d'objet avec un initialiseur d'objet avec un arbre d'expressions? Je veux dire créer un arbre d'expression pour construire ce lambda:

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

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

Comment créer ce lambda avec un arbre d'expression?

METTRE À JOUR:

Je me suis essayé et écris le code suivant:

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

Mais il jette l'erreur suivante:

Impossible de sauter à une étiquette non définie ''.

Est-ce que tout le monde peut m'aider s'il vous plait?

Réponse acceptée

Pour représenter les initialiseurs d'objet dans une expression, vous devez utiliser 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);
}

Pour vérifier que cela fait réellement ce que vous voulez, vous pouvez appeler ToString() sur l'expression créée. Dans ce cas, la sortie est comme prévu:

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

Réponse populaire

Finalement j'ai trouvé ma réponse:

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

METTRE À JOUR:

Bien que cela fonctionne bien, mais @svick fournit un moyen meilleur et plus court dans sa réponse qui est en fait ce que je cherchais: MemberInit . S'il vous plaît voir la réponse de @ svick.



Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi