2010-02-19 98 views
3

我試圖建立類似動態的C#類型initalizer:C#動態類型初始化

MyClass class = new MyClass { MyStringProperty= inputString }; 

我想建立一個反映在給定類型而返回它創建了一個新的委託泛型方法類的實例並根據輸入參數填充它。該方法的簽名可能是這樣的:

Func<string,T> CreateFunc<T>(); 

並調用結果函數將創建「T」的新實例(例如)每輛公共屬性類型爲String的到輸入字符串參數的值。

所以假設「MyClass的」只有MyStringProperty,下面的代碼會在一開始的功能等效於代碼:

var func = CreateFunc<MyClass>(); 
func.Invoke(inputString); 

我很熟悉的System.Reflection和System.Linq的。表達式名稱空間,過去我做了一些中等複雜的事情,但是這個讓我很難過。我想要構建一個編譯的委託,而不是簡單地使用反射遍歷屬性。

謝謝!

回答

1

呃,是的,所以我只是讓自己變得太複雜了。這是我正在尋找的方法:

public static Func<string, T> CreateFunc<T>() 
    where T : class 
{ 
    var properties = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.SetProperty); 
    var param = Expression.Parameter(typeof(string),"o"); 
    var constructorInfo = typeof(T).GetConstructor(new Type[] { }); 
    List<MemberBinding> bindings = new List<MemberBinding>(); 
    foreach (var property in properties) 
     bindings.Add(Expression.Bind(property, param)); 

    var memberInit = Expression.MemberInit(Expression.New(constructorInfo), bindings); 

    var func = Expression.Lambda<Func<string, T>>(memberInit, new ParameterExpression[] {param}).Compile(); 

    return func;    
} 
+0

看起來你還在使用反射,你只是(本質上)緩存反射的結果。 – Randolpho 2010-02-19 21:16:29

+0

很酷,我忘了有關於屬性初始化的表達式節點類型,並且假定需要幾個單獨的語句。@Randolpho,是的,這就是我在對你的回答的評論中試圖解釋的。 – 2010-02-19 22:49:29

+0

是的,我沒有意識到初始化器存在,只是假設我必須自己創建。當我寫這個問題時,這比我想象的要簡單。 – Paul 2010-02-20 01:06:22

1

在CLR 4.0中,您將能夠使用表達式構建完整的語句。

在此之前,你正在尋找一個代碼工作。最簡單的原型方法是在StringBuilder中構建C#,然後調用編譯器。隨着緩存它會表現良好。

這樣做的核心方法是生成IL並使用Reflection Emit來構建方法,從而避免調用編譯器。

0

不幸的是,我沒有看到發生這種情況,雖然我不是專家,但對於表達式和代表可以做深層次的vodoo。

我看到它的方式,你只能用反射來做到這一點。沒有反思,你需要在編譯時知道你想設置的每個屬性的名稱是什麼。你可以爲你想要支持的每個單獨的類做單獨的功能,但這似乎與通用的,一刀切的功能的要求相反。

請問爲什麼功能在第一位?某種形式的依賴注入?

+0

不,這當然是可以的。反射發出(或者在運行時生成的C#源代碼的字符串上調用編譯器)使您可以在運行時以小的延遲突發有效地繼續編譯過程。您使用反射來獲取信息,並從中構建代碼,並緩存生成的委託,以便您不必再次執行反射。 – 2010-02-19 19:34:41

+0

之所以這樣,是因爲我必須部署一個程序集,以後我將無法進行更改,但我不想在當前類型上創建很大的依賴關係。我很確定我只是想出了它,我會發布我想出來的任何東西。 – Paul 2010-02-19 19:36:05