由于一些无效的IL代码,将简单类转换为IL失败了吗?

时间:2015-08-24 00:01:13

标签: c# dynamic reflection reflection.emit il

我试图将这个简单的类转换为IL代码:

public class IL {
  Dictionary<string, int> props = new Dictionary<string, int>() { {"1",1} };
}

事实上,在尝试使用ILDasm动态创建类之前,我使用Emit来了解IL指令。结果显示:

.class public auto ansi beforefieldinit IL
   extends [mscorlib]System.Object
{
 .field private class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32> props
 .method public hidebysig specialname rtspecialname 
      instance void  .ctor() cil managed
 {
 // 
 .maxstack  4
 .locals init (class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32> V_0)
 IL_0000:  ldarg.0
 IL_0001:  newobj     instance void class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32>::.ctor()
 IL_0006:  stloc.0
 IL_0007:  ldloc.0
 IL_0008:  ldstr      "1"
 IL_000d:  ldc.i4.1
 IL_000e:  callvirt   instance void class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32>::Add(!0,
                                                                                                              !1)
 IL_0013:  ldloc.0
 IL_0014:  stfld      class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32> IL::props
 IL_0019:  ldarg.0
 IL_001a:  call       instance void [mscorlib]System.Object::.ctor()
 IL_001f:  ret
 } // end of method IL::.ctor

} // end of class IL

从那以后,我尝试使用Emit这样:

var aBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(new System.Reflection.AssemblyName("test"), AssemblyBuilderAccess.Run);
var mBuilder = aBuilder.DefineDynamicModule("module");
var tBuilder = mBuilder.DefineType("IL");        
var field = tBuilder.DefineField("props", typeof(Dictionary<string, int>), System.Reflection.FieldAttributes.Private);
var con = tBuilder.DefineConstructor(System.Reflection.MethodAttributes.Public | 
                       System.Reflection.MethodAttributes.HideBySig | 
                       System.Reflection.MethodAttributes.SpecialName | 
                       System.Reflection.MethodAttributes.RTSpecialName, 
                       System.Reflection.CallingConventions.HasThis, Type.EmptyTypes);

var conIL = con.GetILGenerator();            
conIL.Emit(OpCodes.Ldarg_0);            
conIL.Emit(OpCodes.Newobj, typeof(Dictionary<string,int>).GetConstructor(Type.EmptyTypes));                        
conIL.Emit(OpCodes.Stloc_0);                
conIL.Emit(OpCodes.Ldloc_0);
conIL.Emit(OpCodes.Ldstr, "1");
conIL.Emit(OpCodes.Ldc_I4_1);
conIL.Emit(OpCodes.Callvirt, typeof(Dictionary<string, int>).GetMethod("Add"));
conIL.Emit(OpCodes.Ldloc_0);
conIL.Emit(OpCodes.Stfld, field);

conIL.Emit(OpCodes.Ldarg_0);
conIL.Emit(OpCodes.Call, typeof(object).GetConstructor(Type.EmptyTypes));
conIL.Emit(OpCodes.Ret);

现在尝试使用它:

var t =  tBuilder.CreateType();
var instance = Activator.CreateInstance(t);//exception has been thrown here 
               //saying "Common Language Runtime detected an invalid program."

这意味着IL代码在某些时候会出错。但是将它与ILDasm实际生成的内容进行比较,我看不出有任何区别。这有什么不对?

1 个答案:

答案 0 :(得分:6)

您错过了声明IL_0006,IL_0007和IL_0013行中引用的局部变量。添加以下行,它将起作用。

conIL.DeclareLocal(typeof (Dictionary<string, int>), false);

编译器最有可能引入本地,因为代码是在调试模式下编译的。