I'm trying to convert this simple class to IL code:
public class IL {
Dictionary<string, int> props = new Dictionary<string, int>() { {"1",1} };
}
In fact I used ILDasm
to know the IL instructions before trying to use Emit
to create the class dynamically. The result it shows is:
.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
From that, I tried using Emit
like this:
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);
Now try using it:
var t = tBuilder.CreateType();
var instance = Activator.CreateInstance(t);//exception has been thrown here
//saying "Common Language Runtime detected an invalid program."
That means the IL code would be wrong at some point. But comparing it with what is actually generated by ILDasm
, I don't see any difference. What is wrong here?
You missed to declare the local variable that is referenced in line IL_0006, IL_0007 and IL_0013. Add the following line and it will work.
conIL.DeclareLocal(typeof (Dictionary<string, int>), false);
Most likely this local was introduced by the compiler, because the code was compiled in debug mode.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With