2015-08-24 34 views
5

Próbuję przekonwertować tę prostą klasę do kodu IL:Konwersja prostej klasy do IL nie powiodła się z powodu nieprawidłowego kodu IL?

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

W rzeczywistości użyłem ILDasm znać instrukcji IL przed próbuje użyć Emit stworzyć klasę dynamicznie. Wynik pokazuje to:

.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 

tym, próbowałem za pomocą Emit tak:

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

Teraz spróbuj go używać:

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

Oznacza to, że kod IL będzie źle w pewnym momencie. Ale porównując go z tym, co faktycznie zostało wygenerowane przez ILDasm, nie widzę żadnej różnicy. Co jest nie tak?

Odpowiedz

6

Utraciłeś, aby zadeklarować zmienną lokalną, do której odwołuje się linia IL_0006, IL_0007 i IL_0013. Dodaj następującą linię i zadziała.

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

Najprawdopodobniej ten lokalny został wprowadzony przez kompilator, ponieważ kod został skompilowany w trybie debugowania.

+0

dziękuję, byłoby dobrze, gdybym lepiej zrozumiał IL. – Hopeless