简体   繁体   中英

How to translate IL to Emit statements?

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.

I have not much worked on Reflection.Emit but when i usually did, i used to use PEVerify command in VS command prompt. It tells what is wrong with the assembly generated. Hope it helps.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM