2012-10-03 31 views
13

¿Hay alguna forma de crear una instancia de un objeto con el inicializador de objetos con un Árbol de expresiones? Me refiero a crear un árbol de expresión para construir este lambda:Expresión para crear una instancia con el inicializador de objetos

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

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

¿Cómo puedo crear este lambda con una expresión de árbol?

ACTUALIZACIÓN:

He probado a mí mismo y escribir código siguiente:

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

Pero tiros el siguiente error:

Cannot jump to undefined label ''.

Todo el mundo puede ayudarme por favor?

+0

¿Puede usted leer mi mensaje: http://www.abhisheksur.com/2010/09/use-of-expression-trees-in-lamda-c. html para generar usted mismo? – abhishek

+0

Gracias al enlace, parece una gran arícula. Pero desafortunadamente soy un tipo nuevo en expresión y tu artículo es muy pesado. ¿Puedes publicar tu sugerencia por favor? –

Respuesta

41

Representar inicializadores de objeto en una expresión, se debe utilizar 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); 
} 

Para verificar esto en realidad hace lo que quiere, puede llamar ToString() en la expresión creada. En este caso, la salida es el esperado:

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

@svick muchas gracias: D lo que estaba buscando en realidad es 'MemberInit'. gracias de nuevo. +1 y aceptar –

3

Finalmente encontré mi respuesta:

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

ACTUALIZACIÓN:

A pesar de que funciona bien, pero @svick proporcionar una manera mejor y más corto en su respuesta que es actuallt Wath que estaba buscando : MemberInit. Por favor, vea la respuesta de @ svick.

+0

Si todo lo que quiere hacer es compilar y ejecutar el código, esto funcionará bien. Pero si desea utilizar la expresión de alguna otra forma (por ejemplo, en LINQ to SQL), es posible que esto no funcione. Lo que debería funcionar es usar 'MemberInit()', como en mi respuesta. De esta forma también obtendrá un código más corto y más legible. – svick

+0

@svick muchas gracias. Quiero hacer compilar y almacenar en caché el func para usar feture. –

Cuestiones relacionadas