Here is the C# code:
public class Calc1 : ICalculator
{
public int Calculate(int x, int y)
{
return x + y;
}
}
Here is the IL:
.method public hidebysig newslot virtual final
instance int32 Calculate(int32 x,
int32 y) cil managed
{
// Code size 9 (0x9)
.maxstack 2
.locals init ([0] int32 CS$1$0000)
IL_0000: nop
IL_0001: ldarg.1
IL_0002: ldarg.2
IL_0003: add
IL_0004: stloc.0
IL_0005: br.s IL_0007
IL_0007: ldloc.0
IL_0008: ret
} // end of method Calc1::Calculate
How can I translate the IL above to Emit statements? Here is my try of translating lines one by one, but got an 'System.InvalidProgramException'.
string methodName = "Calculate";
MethodBuilder getFieldMethod = typeBuilder.DefineMethod(methodName, MethodAttributes.Public | MethodAttributes.Virtual, typeof(int), new Type[] { typeof(int), typeof(int) });
ILGenerator methodIL = getFieldMethod.GetILGenerator();
Label iL0007Label = methodIL.DefineLabel();
methodIL.Emit(OpCodes.Nop);
methodIL.Emit(OpCodes.Ldarg_1);
methodIL.Emit(OpCodes.Ldarg_2);
methodIL.Emit(OpCodes.Add);
methodIL.Emit(OpCodes.Stloc_0);
methodIL.Emit(OpCodes.Br_S, iL0007Label);
methodIL.MarkLabel(iL0007Label);
methodIL.Emit(OpCodes.Ldloc_0);
methodIL.Emit(OpCodes.Ret);
What's wrong with my Emit statements?
You forgot to declare the local variable:
ILGenerator methodIL = getFieldMethod.GetILGenerator();
methodIL.DeclareLocal(typeof(int)); // THIS ONE!
Label iL0007Label = methodIL.DefineLabel();
And technically you forgot the MethodAttributes.Final
, but I don't know if you want to add it.
Note that the opcodes you got are probably for a debug build. If you want to look at the opcodes, I suggest using release builds that use less opcodes.
ILGenerator methodIL = getFieldMethod.GetILGenerator();
methodIL.Emit(OpCodes.Ldarg_1);
methodIL.Emit(OpCodes.Ldarg_2);
methodIL.Emit(OpCodes.Add);
methodIL.Emit(OpCodes.Ret);
is enough for what you want, without even using a local variable.