2009-12-29 105 views
3

我的問題是這樣的:ConstructorInfo.Invoke的DynamicMethod,我需要考慮什麼?

如果我要建立一個DynamicMethod對象,對應於ConstructorInfo.Invoke電話,做什麼類型的IL我需要,以實現應對所有(或大部分)類型當我能保證在我打電話之前要傳遞正確的類型和數量的參數?


背景

我對我的我的IoC容器的第3次迭代,目前做了一些分析,以找出是否有任何方面,我可以很容易刮掉大量的時間正在使用。

我注意到的一件事是,當解析爲一個具體類型時,最終我最終調用了一個構造函數,使用ConstructorInfo.Invoke,傳入一個我已經計算出來的參數數組。

我注意到的是,invoke方法有很多開銷,我想知道這是否只是我做的同樣的檢查的不同實現。例如,由於我有構造函數匹配代碼,爲了找到一個匹配的構造函數,用於我傳入的預定義的參數名稱,類型和值,這個特定的調用調用不會以某種方式結束它應該能夠以正確的順序,正確的類型和適當的值處理正確數量的參數。

在做包含萬個電話給我解決方法的分析會話,然後用DynamicMethod實現模仿調用調用替換它,仿形時序是這樣的:

  • ConstructorInfo.Invoke:1973ms
  • DynamicMethod的:93ms

這佔了20%左右這個分析應用程序的總運行時間。換句話說,通過使用相同的DynamicMethod替換ConstructorInfo.Invoke調用,我可以在處理基本的工廠作用域服務(即所有解析調用以構造函數調用結束)時削減20%的運行時間。

我認爲這是相當可觀的,並且需要仔細研究在此上下文中爲構造函數構建穩定的DynamicMethod生成器的工作量。

所以,動態方法將接受一個對象數組,並返回構造的對象,並且我已經知道有問題的ConstructorInfo對象。

因此,它看起來像動態方法會由以下的IL:

l001: ldarg.0  ; the object array containing the arguments 
l002: ldc.i4.0  ; the index of the first argument 
l003: ldelem.ref ; get the value of the first argument 
l004: castclass T ; cast to the right type of argument (only if not "Object") 
(repeat l001-l004 for all parameters, l004 only for non-Object types, 
varying l002 constant from 0 and up for each index) 
l005: newobj ci ; call the constructor 
l006: ret 

還有什麼我需要考慮?

注意,我知道,創建動態方法運行在「減少訪問模式」的應用程序(有時大腦就不會放棄這些條款)時,可能會無法使用,但在這種情況下,我可以很容易地檢測並且像以前一樣調用原始的構造函數,開銷和所有。

回答

1

對於值類型步驟L004應l004: unbox.any T

找出正確的IL你需要生成最簡單的方法是看通過使用一些測試代碼C#編譯器生成的內容。

static void Test(object[] args) 
{ 
    TestTarget((string)args[0], (int)args[1], (DateTime?)args[2]); 
} 

static void TestTarget(string s, int i, DateTime? dt){} 

編譯爲:

 
L_0000: ldarg.0 
L_0001: ldc.i4.0 
L_0002: ldelem.ref 
L_0003: castclass string 
L_0008: ldarg.0 
L_0009: ldc.i4.1 
L_000a: ldelem.ref 
L_000b: unbox.any int32 
L_0010: ldarg.0 
L_0011: ldc.i4.2 
L_0012: ldelem.ref 
L_0013: unbox.any [mscorlib]System.Nullable`1<valuetype [mscorlib]System.DateTime> 
L_0018: call void Program::TestTarget(string, int32, valuetype [mscorlib]System.Nullable`1<valuetype [mscorlib]System.DateTime>) 
L_001d: ret 
+0

所以基本上,因爲我的Type對象的每個參數,如果Type.IsValueType返回,而不是castclass TYPE真的,我用unbox.any TYPE呢? – 2009-12-29 19:01:17

+0

是的,這應該足以涵蓋所有參數類型。 – 2009-12-29 21:17:14

+0

謝謝,我會添加一堆單元測試來驗證我能想到的所有組合,但是這看起來可能只是工作:) – 2009-12-29 21:54:53

0

有可更容易,速度更快與反思工作庫。例如,Fasterflect可以生成用於調用任何構造函數的IL - 您只需將它傳遞給您想要在構造函數上使用的參數即可。

// note: class must have constructor with (int,string,string) signature 
object obj = someType.CreateInstance(new { id=1, name="jens", foo="bar" }); 

該庫還能夠探測一個合適的構造函數調用,如果你沒有一組構造函數完全匹配的參數。

// try to map id, name and foo to constructor parameters 
// allows changing the order and permit fallback to setting fields/properties 
// e.g. might result in call to ctor(string,string) and set field "id" 
object obj = someType.TryCreateInstance(new { id=1, name="jens", foo="bar" }); 

聲明:我作爲貢獻者參與了上述項目。

相關問題