2016-07-31 12 views
4

実行時に次のコードをILコードとして出力しようとしました。InvalidProgramException(無効なILコード)ですか?

class TestObject { 
     public int Hello {get;set;} 
     public int Test {get;set;} 
    } 

    static TestObject test(BinaryReader reader) { 
     var a = new TestObject(); 
     a.Hello = reader.ReadInt32(); 
     a.Test = reader.ReadInt32(); 
     return a; 
    } 

LINQPadは示しています

test: 
IL_0000: nop   
IL_0001: newobj  UserQuery+TestObject..ctor 
IL_0006: stloc.0  // a 
IL_0007: ldloc.0  // a 
IL_0008: ldarg.0  
IL_0009: callvirt System.IO.BinaryReader.ReadInt32 
IL_000E: callvirt UserQuery+TestObject.set_Hello 
IL_0013: nop   
IL_0014: ldloc.0  // a 
IL_0015: ldarg.0  
IL_0016: callvirt System.IO.BinaryReader.ReadInt32 
IL_001B: callvirt UserQuery+TestObject.set_Test 
IL_0020: nop   
IL_0021: ldloc.0  // a 
IL_0022: stloc.1  
IL_0023: br.s  IL_0025 
IL_0025: ldloc.1  
IL_0026: ret   

は、C#でそれを再現しようとすると:

 var method = new DynamicMethod("DynamicCreate", typeof(TestSubject), new Type[] {typeof(BinaryReader)}, 
      typeof(TestSubject).Module); 
     var il = method.GetILGenerator(); 

     var properties = from property in typeof(TestSubject).GetProperties() 
      let orderAttribute = 
       property.GetCustomAttributes(typeof(OrderAttribute), false).SingleOrDefault() as OrderAttribute 
      orderby orderAttribute.Order 
      select property; 

     il.Emit(OpCodes.Nop); 
     il.Emit(OpCodes.Newobj, typeof(TestSubject).GetConstructors()[0]); // pushes a new instance of testsubject on the stack 
     il.Emit(OpCodes.Stloc_0); // pop the instance to local variable 0 
     foreach (var prop in properties) 
     { 
      il.Emit(OpCodes.Ldloc_0); // load local variable 0 
      il.Emit(OpCodes.Ldarg_0); // load argument 0 (the binary reader) 
      il.Emit(OpCodes.Callvirt, typeof(BinaryReader).GetMethod("ReadInt32", BindingFlags.Public | BindingFlags.Instance)); // call the binary reader method (ReadInt32) 
      il.Emit(OpCodes.Callvirt, prop.SetMethod); // call the setter of the property (instance of local variable 0 and return value of readint32) 
      il.Emit(OpCodes.Nop); 
     } 
     il.Emit(OpCodes.Ldloc_0); 
     il.Emit(OpCodes.Stloc_1); 
     var label = il.DefineLabel(); 
     il.Emit(OpCodes.Br_S, label); 
     il.MarkLabel(label); 
     il.Emit(OpCodes.Ldloc_1); // push the test subject instance 
     il.Emit(OpCodes.Ret); // and return 

     var generator = (Load)method.CreateDelegate(typeof(Load)); 
     var reader = new BinaryReader(new MemoryStream(new byte[] {1, 2, 3, 4, 0, 0, 0, 1})); 
     var test = generator(reader); // exception here 

TestSubjectクラス:

public class TestSubject 
{ 

    [Order] 
    public int Test1 { get; set; } 

    [Order] 
    public int Test2 { get; set; } 

} 

私に次の例外を与える:

System.InvalidProgramException { "共通言語ランタイムハットEIN ungültigesののprogramm gefundenダイ。"}は

はそれで何が悪いのでしょうか?

答えて

3

地元の人々を宣言する必要があります。また、コードを単純化することもできます(ILはデバッグビルドで生成されました)。

il.DeclareLocal(typeof(TestSubject)); 

il.Emit(OpCodes.Newobj, typeof(TestSubject).GetConstructors()[0]); // pushes a new instance of testsubject on the stack 
il.Emit(OpCodes.Stloc_0); // store the instance in local variable 0 
foreach (var prop in properties) 
{ 
    il.Emit(OpCodes.Ldloc_0); // load local variable 0 
    il.Emit(OpCodes.Ldarg_0); // load argument 0 (the binary reader) 
    il.Emit(OpCodes.Callvirt, typeof(BinaryReader).GetMethod("ReadInt32", BindingFlags.Public | BindingFlags.Instance)); // call the binary reader method (ReadInt32) 
    il.Emit(OpCodes.Callvirt, prop.SetMethod); // call the setter of the property (instance of local variable 0 and return value of readint32) 
} 
il.Emit(OpCodes.Ldloc_0); // push the test subject instance 
il.Emit(OpCodes.Ret); // and return 
+0

これは私にとってはうまくいくものです。しかし、私が言及したように、私は今表現木で作業しました。そして私はそれが大好きです。この質問は私にとって良い学習効果をもたらしました。 – AmazingTurtle

1

あなたは地方を定義しませんでした。

また、ここでのILはデバッグモード出力からのものです。それは必要以上に複雑です。

Reflection Emitはほとんど廃止されています(場合によってはまだ必要です)。式ツリーを使ってこのようなコードを生成するほうがはるかに簡単です。このコードをすべて削除し、それを式ツリーで置き換えます。

関連する問題