请解释在 .NET 平台中,如何使用 IL Emit 来实现代码的动态生成与执行?
考察说明
考查对 .NET 底层元数据和 IL 指令的了解,以及动态程序集构建流程的掌握。
回答思路
- 【回答框架 1】IL Emit 是 System.Reflection.Emit 命名空间提供的一组 API,允许在运行时动态创建程序集、模块、类型和方法。其核心目标是生成托管代码的元数据与中间语言指令,而非直接生成机器码。
- 【回答框架 2】典型流程为:先创建动态程序集(AssemblyBuilder)和模块(ModuleBuilder),再定义类型(TypeBuilder)与方法(MethodBuilder),通过 ILGenerator 的 Emit 方法发出 IL 指令,最后调用 CreateType 使类型可用,并用反射创建实例和调用方法。
- 【回答框架 3】实现动作分为几种:一是生成新类型和完整方法体;二是动态方法(DynamicMethod),无需程序集和类型即可生成轻量方法;三是修改现有方法的 IL,但只能整体替换,无法在运行时直接改写原方法体。
- 【回答框架 4】执行时,动态生成的类型或方法在首次调用时由 JIT 编译为机器码。相比反射调用,动态方法在预先生成委托(如 Func 或 Action)后,调用开销接近普通方法,比纯反射更快。
- 【回答框架 5】需确保生成的 IL 类型匹配、栈深度正确和分支目标有效,否则会在 JIT 阶段抛出 InvalidProgramException 或 BadImageFormatException。可用工具如 ILDasm 或 dnSpy 验证生成的 IL。
- 【关键点 1】核心是 System.Reflection.Emit 下的 AssemblyBuilder、TypeBuilder、MethodBuilder 和 ILGenerator。
- 【关键点 2】轻量场景优先用 DynamicMethod,无需完整程序集,性能接近原生调用。
- 【关键点 3】生成后必须先调用 CreateType(对于 TypeBuilder)让类型生效。
- 【关键点 4】使用 Emit 时需注意 IL 栈平衡和类型约束。
- 【关键点 5】动态代码的安全与版本依赖需提前评估,避免引入不稳定方案。
- 【易错点 1】不要认为 IL Emit 能直接生成可执行的机器码,它生成的是 IL,需 JIT 编译。
- 【易错点 2】不要混淆 DynamicMethod 与 MethodBuilder 的适用范围,前者适合简单方法,后者适合完整类型定义。
- 【易错点 3】生成环境需有 Reflection.Emit 权限,在部分 AOT 或受限环境下可能不可用。