2012-10-03 69 views
13

有沒有什麼方法可以用對象初始值設定器和表達式樹來創建對象的實例?我的意思是創建一個表達式樹構建這個拉姆達:用對象初始化器創建實例的表達式

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

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

如何創建這個拉姆達與表達式樹?

UPDATE:

我tryed自己寫下面的代碼:

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

但它引發以下錯誤:

Cannot jump to undefined label ''.

大家可以幫我嗎?

+0

你能閱讀我的文章:http://www.abhisheksur.com/2010/09/use-of-expression-trees-in-lamda-c。 html來生成自己? – abhishek

+0

感謝鏈接,它似乎是一個巨大的文章。但不幸的是,我是一個表達新人,你的文章非常重要。你能發表你的建議嗎? –

回答

41

,代表了一個表達的對象初始化,您應該使用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); 
} 

爲了驗證這一點其實你想要做什麼,你可以在創建表達致電ToString()。在這種情況下,如預期的輸出:

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

@svick非常非常感謝你:D我正在尋找的是'MemberInit'。再次感謝你。 +1並接受 –

3

終於讓我找到我的答案:

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:

雖然它工作正常,但@svick提供他的回答更好和更短的方式,是actuallt wath我一直在尋找:MemberInit。請參閱@ svick的答案。

+0

如果你只想編譯和執行代碼,這將會很好。但是,如果你想以某種其他方式使用表達式(例如在LINQ to SQL中),這可能無法正常工作。應該使用'MemberInit()',就像我的答案一樣。這樣你也可以得到更短,更易讀的代碼。 – svick

+0

@svick太感謝你了。我想編譯和緩存函數來使用。 –