如何将 IL 翻译成 Emit 语句?
How to translate IL to Emit statements?
这是 C# 代码:
public class Calc1 : ICalculator
{
public int Calculate(int x, int y)
{
return x + y;
}
}
这是 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[=11=]00)
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
如何将上述 IL 转换为 Emit 语句?
这是我逐行翻译的尝试,但得到了 '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);
我的 Emit 语句有什么问题?
我在 Reflection.Emit 上的工作不多,但当我通常这样做时,我曾经在 VS 命令提示符下使用 PEVerify
命令。它告诉生成的程序集有什么问题。希望对你有帮助。
您忘记声明局部变量:
ILGenerator methodIL = getFieldMethod.GetILGenerator();
methodIL.DeclareLocal(typeof(int)); // THIS ONE!
Label iL0007Label = methodIL.DefineLabel();
从技术上讲,您忘记了 MethodAttributes.Final
,但我不知道您是否要添加它。
请注意,您获得的操作码可能用于调试版本。如果您想查看操作码,我建议使用使用较少操作码的发布版本。
ILGenerator methodIL = getFieldMethod.GetILGenerator();
methodIL.Emit(OpCodes.Ldarg_1);
methodIL.Emit(OpCodes.Ldarg_2);
methodIL.Emit(OpCodes.Add);
methodIL.Emit(OpCodes.Ret);
足以满足您的需求,甚至无需使用局部变量。
这是 C# 代码:
public class Calc1 : ICalculator
{
public int Calculate(int x, int y)
{
return x + y;
}
}
这是 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[=11=]00)
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
如何将上述 IL 转换为 Emit 语句? 这是我逐行翻译的尝试,但得到了 '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);
我的 Emit 语句有什么问题?
我在 Reflection.Emit 上的工作不多,但当我通常这样做时,我曾经在 VS 命令提示符下使用 PEVerify
命令。它告诉生成的程序集有什么问题。希望对你有帮助。
您忘记声明局部变量:
ILGenerator methodIL = getFieldMethod.GetILGenerator();
methodIL.DeclareLocal(typeof(int)); // THIS ONE!
Label iL0007Label = methodIL.DefineLabel();
从技术上讲,您忘记了 MethodAttributes.Final
,但我不知道您是否要添加它。
请注意,您获得的操作码可能用于调试版本。如果您想查看操作码,我建议使用使用较少操作码的发布版本。
ILGenerator methodIL = getFieldMethod.GetILGenerator();
methodIL.Emit(OpCodes.Ldarg_1);
methodIL.Emit(OpCodes.Ldarg_2);
methodIL.Emit(OpCodes.Add);
methodIL.Emit(OpCodes.Ret);
足以满足您的需求,甚至无需使用局部变量。