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

本文关键字:IL 简单 转换 失败 于一些 无效 代码 | 更新日期: 2023-09-27 18:09:31

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

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

事实上,在尝试使用Emit动态创建类之前,我使用ILDasm来了解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相比,我看不出有什么不同。这里出了什么问题?

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

您没有声明在IL_0006、IL_0007和IL_0013行中引用的局部变量。添加下面这行代码就可以了。

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

这个局部很可能是编译器引入的,因为代码是在调试模式下编译的。