1

我正在尝试使用 .NET 中的反射和发射生成动态程序集。我收到错误消息“公共语言运行时检测到无效程序”。我创建了另一个程序,它具有我想要使用硬编码类型的功能。我尝试编写的功能最终将使用动态类型,但我可以使用 ILDasm 来查看我需要生成的 IL。我正在将我生成的 IL 与编译器生成的 IL 进行比较。在一种方法的 .locals init 声明中,我看到编译器生成的代码中有一个额外的项目,

编译器生成:

.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”可能指的是 Entity<> 的泛型类型,但我不确定,我想知道 ILDasm 输出是否有一个键可以向我解释它更晦涩的输出。

4

1 回答 1

1

该规范可在此处免费获得。这需要一点时间来适应,但是一旦你弄清楚了结构,大部分细节都很容易找到。

!!列在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>()!!0将是T,并且!!1将是U

然而,这[0]是一个很好的问题。该规范似乎没有解决它。该.locals指令在II.15.4.1.3 .locals 指令中进行了描述,该指令将语法列为

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

[0]除非它是 a 的一部分,否则似乎没有任何东西允许在那里Type,并且Type不允许任何以[两者开头的东西。我的猜测是,这是 Microsoft 实现特有的一个未记录的特性,旨在帮助人类读者看到位置 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],组装并立即反汇编结果,表明变量已重新排序。

于 2013-09-23T18:34:14.193 回答