System.Reflection.Emit - If 语句生成
System.Reflection.Emit - If Statement Generation
我正在尝试了解如何在 C# 中使用 ILGenerator 生成 If
语句。
这是我的代码:(ilg 是一个 ILGenerator)
ilg.Emit(OpCodes.Ldc_I4_1);
Label start = ilg.DefineLabel();
ilg.Emit(OpCodes.Brfalse, start);
ilg.Emit(OpCodes.Ldstr, "Hello");
ilg.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }));
ilg.MarkLabel(start);
一些注意事项:
- 单独调用 Console.WriteLine 效果很好。
- 这是我在 运行 生成的 exe:
时得到的错误
Unhandled Exception: System.InvalidProgramException: Common Language Runtime detected an invalid program. at Testing.Test.Main(String[] )
您的代码几乎可以正常工作,您只是忘记在末尾添加 OpCodes.Ret
,查看有效的代码:
public static void Main(string[] args)
{
var dynamicMethod = new DynamicMethod("PrintHello", typeof(void), null);
var ilGenerator = dynamicMethod.GetILGenerator();
ilGenerator.Emit(OpCodes.Ldc_I4_1);
var toEnd = ilGenerator.DefineLabel();
ilGenerator.Emit(OpCodes.Brfalse, toEnd);
ilGenerator.Emit(OpCodes.Ldstr, "Hello");
ilGenerator.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }));
ilGenerator.MarkLabel(toEnd);
ilGenerator.Emit(OpCodes.Ret);
var @delegate = (Action)dynamicMethod.CreateDelegate(typeof(Action));
@delegate();
}
然后你会得到这个输出
Hello
如果你评论这一行 ilGenerator.Emit(OpCodes.Ret);
你会得到这个异常
System.InvalidProgramException
: Common Language Runtime detected an invalid program.
记住,C# 中的每个方法都必须有 OpCode.Ret
如果你的 Main 方法是空的,像这样
public static void Main(string[] args)
{
}
生成的 IL(在调试模式下,没有优化)将是这样的
.method public hidebysig static void Main (string[] args) cil managed
{
// Method begins at RVA 0x2050
// Code size 2 (0x2)
.maxstack 8
.entrypoint
IL_0000: nop
IL_0001: ret
} // end of method Program::Main
生成的IL(在release模式下,with优化)会是这个
.method public hidebysig static void Main (string[] args) cil managed
{
// Method begins at RVA 0x2050
// Code size 1 (0x1)
.maxstack 8
.entrypoint
IL_0000: ret
} // end of method Program::Main
我正在尝试了解如何在 C# 中使用 ILGenerator 生成 If
语句。
这是我的代码:(ilg 是一个 ILGenerator)
ilg.Emit(OpCodes.Ldc_I4_1);
Label start = ilg.DefineLabel();
ilg.Emit(OpCodes.Brfalse, start);
ilg.Emit(OpCodes.Ldstr, "Hello");
ilg.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }));
ilg.MarkLabel(start);
一些注意事项:
- 单独调用 Console.WriteLine 效果很好。
- 这是我在 运行 生成的 exe: 时得到的错误
Unhandled Exception: System.InvalidProgramException: Common Language Runtime detected an invalid program. at Testing.Test.Main(String[] )
您的代码几乎可以正常工作,您只是忘记在末尾添加 OpCodes.Ret
,查看有效的代码:
public static void Main(string[] args)
{
var dynamicMethod = new DynamicMethod("PrintHello", typeof(void), null);
var ilGenerator = dynamicMethod.GetILGenerator();
ilGenerator.Emit(OpCodes.Ldc_I4_1);
var toEnd = ilGenerator.DefineLabel();
ilGenerator.Emit(OpCodes.Brfalse, toEnd);
ilGenerator.Emit(OpCodes.Ldstr, "Hello");
ilGenerator.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }));
ilGenerator.MarkLabel(toEnd);
ilGenerator.Emit(OpCodes.Ret);
var @delegate = (Action)dynamicMethod.CreateDelegate(typeof(Action));
@delegate();
}
然后你会得到这个输出
Hello
如果你评论这一行 ilGenerator.Emit(OpCodes.Ret);
你会得到这个异常
System.InvalidProgramException
: Common Language Runtime detected an invalid program.
记住,C# 中的每个方法都必须有 OpCode.Ret
如果你的 Main 方法是空的,像这样
public static void Main(string[] args)
{
}
生成的 IL(在调试模式下,没有优化)将是这样的
.method public hidebysig static void Main (string[] args) cil managed
{
// Method begins at RVA 0x2050
// Code size 2 (0x2)
.maxstack 8
.entrypoint
IL_0000: nop
IL_0001: ret
} // end of method Program::Main
生成的IL(在release模式下,with优化)会是这个
.method public hidebysig static void Main (string[] args) cil managed
{
// Method begins at RVA 0x2050
// Code size 1 (0x1)
.maxstack 8
.entrypoint
IL_0000: ret
} // end of method Program::Main