2013-09-23 49 views
1

我正嘗試使用反射來生成動態裝配&在.NET中發射。我收到一個錯誤,「通用語言運行時檢測到一個無效的程序。」我創建了另一個具有我想要的硬編碼類型功能的程序。我試圖編寫的功能最終將使用動態類型,但是我可以使用ILDasm來查看我需要生成的IL。我將我生成的IL與編譯器生成的IL進行比較。在.locals初始化一個方法的聲明我看到有在編譯器生成的代碼的附加項目,CLR IL-方形支架在.locals上的重要性初始化

編譯器生成的:

.locals init ([0] class [System.Core]System.Linq.Expressions.ParameterExpression CS$0$0000, 
      [1] class [System.Core]System.Linq.Expressions.ParameterExpression[] CS$0$0001) 

礦:

.locals init (class [System.Core]System.Linq.Expressions.ParameterExpression V_0, 
     class [System.Core]System.Linq.Expressions.ParameterExpression[] V_1) 

我不理解編譯器生成的代碼中「[0]」和「[1]」的含義。誰能告訴我這是什麼意思?

作爲一個更普遍的問題,我可以遵循大多數ILDasm輸出,而不會有太多的麻煩。但我經常碰到一個有問題的表達。舉例來說,在這條線從ILDASM

callvirt instance class [EntityFramework]System.Data.Entity.ModelConfiguration.EntityTypeConfiguration`1<!!0> [EntityFramework]System.Data.Entity.DbModelBuilder::Entity<class DynamicEdmxTrial.HardFooAsset>() 

了「!0」可能指的是通用型的實體<>的,但我不肯定知道,我不知道是否有一個關鍵以ILDasm輸出,這將解釋其更加模糊的輸出給我。

+2

「我收到一個錯誤,」公共語言運行時檢測到一個無效的程序。「」您是否嘗試過在您的程序集上運行PEVerify? – svick

+0

另外,你究竟如何得到這些'.locals'?都來自ILDasm? – svick

+0

「無效的程序」我不太在意。我想我已經找到了。兩個.local聲明來自ILDasm。它顯然發現了C#代碼和我的Reflection.Emit之間的一些區別。 – jrv

回答

1

該規範免費提供here。這需要一點習慣,但大部分細節很容易找到,一旦你找出結構。

!!II.7.1類型列出:

Type ::=  | Description        | Clause 
    ‘!’ Int32 | Generic parameter in a type definition, | §II.9.1 
       | accessed by index from 0    | 
| ‘!!’ Int32 | Generic parameter in a method   | §II.9.2 
       | definition, accessed by index from 0 | 
... 

換言之,即C#稱之爲f<T, U>()!!0T,並!!1U的方法內。

但是,[0]是一個很好的問題。規範似乎沒有解決它。該.locals指令在II.15.4.1.3的.locals指令,其中列出了語法

MethodBodyItem ::= ... 
| .locals [ init ] ‘(’ LocalsSignature ‘)’ 
LocalsSignature ::= Local [ ‘,’ Local ]* 
Local ::= Type [ Id ] 

描述沒有什麼,似乎讓[0]那裏,除非它是一個Type的一部分,並且Type不允許任何以[開頭的任何內容。我的猜測是,這是微軟實施特有的無證的特性,旨在幫助讀者看到位置0是局部變量CS$0$0000,因爲當生成的指令通過索引訪問局部變量時。

用ILAsm進行實驗表明,這正是它的意思。以一個簡單的C#程序:

static class Program { 
    static void Main() { 
     int i = 0, j = 1; 
    } 
} 

和編譯,然後拆卸它(csc test.cs && ildasm /text test.exe >test.il)表示:

.... 
.locals init (int32 V_0, 
     int32 V_1) 
IL_0000: nop 
IL_0001: ldc.i4.0 
IL_0002: stloc.0 
IL_0003: ldc.i4.1 
IL_0004: stloc.1 
IL_0005: ret 
.... 

修改.locals

.locals init ([0] int32 V_0, [0] int32 V_1) 

給出一個有用的警告消息:

test.il(41) : warning : Local var slot 0 is in use 

事實上,聲明不同類型的變量,然後使用[2],[1],[0]重新排序它們,組裝並立即分解結果,顯示變量被重新排序。

+0

我有規範,但正如你所說,它似乎沒有解釋「[0]」,所以我沒有嘗試「!!」。 – jrv

+0

對,這需要一些測試來清除它。 – hvd

+0

我正確的說[0]描述了變量所在的本地插槽,這對於ldloc&stloc指令很重要嗎?只要ldloc&stloc指令加載並存儲到正確的變量插槽,[0]和[1]都很好,但不必要? – jrv