如何输出可供CLR运行的IL代码及在.NET 5中保存动态程序集
方法体生成方案说明
直接使用ILGenerator发射IL不是唯一实现方式,也不是所有场景下的最优选择,你可以根据项目需求选择以下方案:
- 原生
ILGenerator:是.NET内置的最低层IL发射API,优势是无额外依赖、粒度极细、完全可控、运行性能最高,适合生产级编程语言实现,缺点是需要熟悉IL指令集,容易出现栈不平衡、标签跳转错误等问题。 - 封装类IL发射库:比如
Sigil这类第三方库,是对ILGenerator的高层封装,自动处理栈平衡、标签声明顺序等易出错逻辑,API更友好,最终生成的IL质量和手写ILGenerator完全一致,开发效率更高。 - 表达式树(Expression Tree):不需要手动编写IL,通过强类型API构造逻辑结构(分支、循环、变量、方法调用等都支持),自动编译生成IL,开发难度极低,缺点是对部分特殊IL语义(比如异常过滤器、手动栈操作等)支持不全,灵活性低于原生IL发射。
- 生成高层语言源码再编译:直接将你的AST转换为C#/VB代码,通过Roslyn API或者调用编译器直接生成程序集,完全不需要接触IL,开发成本最低,缺点是编译性能低于内存IL发射,且如果你的语言有特殊语义无法映射到C#特性会受限。
.NET 5+ 动态程序集保存方案
不需要切换到.NET Framework 4.8,.NET 5及以上版本已经原生支持动态程序集保存,可选方案如下:
- 官方
System.Reflection.Emit包:直接安装官方NuGet包System.Reflection.Emit,创建AssemblyBuilder时指定AssemblyBuilderAccess.RunAndSave权限,即可直接调用Save()方法将程序集写入磁盘,生成的程序集默认兼容.NET 5/6,无额外适配成本。 Mono.Cecil库:第三方元数据操作库,比官方Emit API功能更丰富,支持读写已有程序集、修改IL、生成全新程序集,兼容性极强,生成的程序集可同时适配.NET Framework和.NET 5+,是很多成熟代码生成工具、编译器的首选后端。- Roslyn编译:如果你选择生成C#源码的方案,可通过
Microsoft.CodeAnalysis.CSharp包在内存直接编译源码输出程序集,也可以直接调用SDK自带的csc编译器完成编译,生成的程序集可自由指定目标框架版本。
只要你生成的程序集没有引用.NET Framework专属的API,以上所有方案输出的程序集都可以正常在.NET 5/6运行。
内容的提问来源于stack exchange,提问作者Jonas _
相关产品推荐
相关产品推荐

