2016-07-31 55 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 { “死公共语言运行库的帽子艾因 ungültigesPROGRAMM 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

这似乎适合我。但是,正如@usr所提到的那样,我现在正在使用表达式树。我喜欢它。这个问题对我有很好的学习效果。 – AmazingTurtle

1

你没有定义当地人。

另外,这里的IL来自调试模式输出。这比需要更复杂一些。

反射发射几乎已过时(某些情况下仍需要)。使用表达式树来生成这样的代码要容易得多。删除所有这些代码并将其替换为表达式树。