2015-08-24 13 views
5

sto cercando di convertire questo semplice classe per codice IL:La conversione della classe semplice in IL è fallita a causa di un codice IL non valido?

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

In realtà ho usato ILDasm conoscere le istruzioni IL prima di tentare di utilizzare Emit per creare la classe in modo dinamico. Il risultato mostra è:

.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 

Da questo, ho provato ad utilizzare Emit come questo:

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); 

Ora provate ad usarlo:

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

Ciò significa che il codice IL sarebbe sbagliato ad un certo punto. Ma confrontandolo con ciò che è effettivamente generato da ILDasm, non vedo alcuna differenza. Cosa c'è di sbagliato qui?

risposta

6

Si è perso per dichiarare la variabile locale a cui si fa riferimento nella riga IL_0006, IL_0007 e IL_0013. Aggiungi la seguente riga e funzionerà.

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

Molto probabilmente questo locale è stato introdotto dal compilatore, perché il codice è stato compilato in modalità debug.

+0

grazie, sarebbe stato OK se avessi capito meglio IL. – Hopeless

Problemi correlati