2012-10-03 15 views
13

Czy istnieje sposób utworzenia instancji obiektu z inicjatorem obiektu za pomocą drzewa wyrażeń? Mam na myśli utworzenie drzewa wyrażeń do zbudowania tego lambda:Wyrażenie, aby utworzyć instancję z inicjatorem obiektu

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

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

Jak mogę utworzyć tę lambdę z drzewem wyrażeń?

UPDATE:

tryed siebie i napisać następujący kod:

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

Ale to rzuca się następujący błąd:

Cannot jump to undefined label ''.

Czy każdy może mi pomóc proszę?

+0

Czy czytasz mój wpis: http://www.abhisheksur.com/2010/09/use-of-expression-trees-in-lamda-c. html do generowania siebie? – abhishek

+0

Dzięki linkowi wydaje się być świetnym pomysłem. Ale niestety jestem nowym facetem w wyrazie, a twój artykuł jest bardzo ważny. Czy możesz opublikować swoją sugestię? –

Odpowiedz

41

Do reprezentowania inicjatorów obiektu w wyrażeniu, należy użyć 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); 
} 

Aby zweryfikować to faktycznie robi to, co chcesz, możesz zadzwonić ToString() na stworzonej wypowiedzi. W takim przypadku dane wyjściowe są zgodne z oczekiwaniami:

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

@svick dziękuję bardzo bardzo: D, czego szukałem faktycznie jest 'MemberInit'. Jeszcze raz dziękuję. +1 i zaakceptuj –

3

końcu znalazłem moją odpowiedź:

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:

Chociaż to działa dobrze, ale @svick zapewnić lepszą i krótszą drogę w swojej odpowiedzi, że jest actuallt wath szukałem : MemberInit. Zobacz odpowiedź @ svick.

+0

Jeśli wszystko, co chcesz zrobić, to skompilować i wykonać kod, to zadziała dobrze. Ale jeśli chcesz użyć wyrażenia w inny sposób (np. W LINQ do SQL), może to nie działać dobrze. Co powinno działać, to użycie 'MemberInit()', jak w mojej odpowiedzi. W ten sposób otrzymasz także krótszy, bardziej czytelny kod. – svick

+0

@ dziękuję za dużo. Chcę skompilować i buforować func do wykorzystania przy użyciu. –

Powiązane problemy