1

.NET で Reflection & Emit を使用して動的アセンブリを生成しようとしています。「共通言語ランタイムが無効なプログラムを検出しました」というエラーが表示されます。ハードコーディングされた型を使用して、必要な機能を持つ別のプログラムを作成しました。私が書こうとしている機能は、最終的には動的な型を使用しますが、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>()!!0T、および!!1となりますU

しかし、これ[0]は良い質問です。仕様はそれに対処していないようです。この.localsディレクティブについては、II.15.4.1.3 .localsディレクティブで説明されています。構文は次のとおりです。

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

の一部で[0]ない限り、そこに許可されているように見えるものは何もなく、いずれかで始まるものは許可されません。私の推測では、これは Microsoft の実装に固有の文書化されていない特異性であり、生成された命令がインデックスによってローカル変数にアクセスする場合に、場所 0 がローカル変数であることを人間の読者が理解できるようにすることを目的としています。TypeType[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 に答える