2012-10-03 7 views
13

Esiste un modo per creare un'istanza di un oggetto con l'inizializzatore di oggetti con un albero di espressione? Voglio dire creare un albero di espressione per costruire questo lambda:Espressione per creare un'istanza con l'inizializzatore di oggetti

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

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

Come posso creare questa lambda con un'espressione Tree?

UPDATE:

io stesso provato e scrivere codice seguente:

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

Ma getta il seguente errore:

Cannot jump to undefined label ''.

Può chiunque aiutarmi per favore?

+0

Puoi leggere il mio post: http://www.abhisheksur.com/2010/09/use-of-expression-trees-in-lamda-c. html per generare te stesso? – abhishek

+0

Grazie al collegamento, sembra un grande aricle. Ma sfortunatamente sono un ragazzo nuovo in espressione e il tuo articolo è molto pesante. Puoi postare il tuo suggerimento per favore? –

risposta

41

Rappresentare inizializzatori oggetto in un'espressione, è necessario utilizzare 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); 
} 

per verificare questo realmente fa ciò che si vuole, è possibile chiamare ToString() sull'espressione creato. In questo caso, l'uscita è come ci si aspetta:

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

@svick grazie davvero molto: D quello che stavo cercando in realtà è 'MemberInit'. grazie ancora. +1 e accetta –

3

finalmente ho trovato la mia risposta:

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:

Anche se funziona bene, ma @svick fornire un modo migliore e più breve nella sua risposta che è actuallt Wath che cercavo : MemberInit. Si prega di vedere la risposta di @ svick.

+0

Se tutto ciò che si vuole fare è compilare ed eseguire il codice, questo funzionerà bene. Ma se si volesse usare l'espressione in qualche altro modo (ad es. In LINQ in SQL), questo potrebbe non funzionare bene. Ciò che dovrebbe funzionare è usare 'MemberInit()', come nella mia risposta. In questo modo otterrai anche un codice più breve e più leggibile. – svick

+0

@svick grazie mille. Voglio compilare e memorizzare nella cache la funzione da utilizzare. –

Problemi correlati