【问题标题】:Converting simple class to IL failed due to some invalid IL code?由于某些无效的 IL 代码,将简单类转换为 IL 失败?
【发布时间】:2015-11-17 07:33:52
【问题描述】:

我正在尝试将这个简单的类转换为 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 实际生成的内容相比,我看不出有什么区别。这里有什么问题?

【问题讨论】:

    标签: c# dynamic reflection reflection.emit il


    【解决方案1】:

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

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

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

    【讨论】:

    • 谢谢,如果我能更好地理解 IL 就好了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多