当前位置:首页 > C# > 正文

C#动态程序集的持久化保存(手把手教你用Emit将运行时生成的程序集保存到磁盘)

在C#开发中,有时我们需要在运行时动态生成代码并编译成程序集(Assembly),这通常通过 System.Reflection.Emit 命名空间实现。然而,默认情况下,这些动态生成的程序集仅存在于内存中,程序结束后就会消失。如果你希望将这些动态程序集持久化保存到磁盘,以便后续加载或分发,本文将为你详细讲解如何操作。

C#动态程序集的持久化保存(手把手教你用Emit将运行时生成的程序集保存到磁盘) C#动态程序集  动态程序集持久化 C# Emit保存程序集 .NET动态代码生成 第1张

什么是动态程序集?

动态程序集是通过 AssemblyBuilder 在运行时创建的程序集。它允许你在程序执行过程中定义新的类型、方法、属性等,常用于插件系统、脚本引擎、ORM映射等高级场景。

为什么需要持久化保存?

虽然动态程序集在内存中运行效率高,但每次启动程序都要重新生成,既浪费资源又影响性能。通过将动态程序集持久化保存为DLL文件,下次可以直接加载使用,提升应用启动速度和稳定性。

准备工作

确保你的项目目标框架支持动态程序集保存。注意:从 .NET Core 3.0 开始,AssemblyBuilder.Save() 方法已被移除。因此,本文适用于 .NET Framework(如 4.7.2 或 4.8)。如果你使用的是 .NET 5/6/7/8,需改用其他方式(如 Roslyn 编译器)生成可保存的程序集。

完整示例:创建并保存动态程序集

下面是一个完整的 C# 示例,演示如何使用 Reflection.Emit 创建一个包含简单类的动态程序集,并将其保存为 MyDynamicAssembly.dll 文件。

using System;using System.Reflection;using System.Reflection.Emit;namespace DynamicAssemblyDemo{    class Program    {        static void Main(string[] args)        {            // 1. 定义程序集名称            AssemblyName assemblyName = new AssemblyName("MyDynamicAssembly");            // 2. 创建可保存的程序集构建器(注意:必须指定 AssemblyBuilderAccess.RunAndSave)            AssemblyBuilder assemblyBuilder =                 AppDomain.CurrentDomain.DefineDynamicAssembly(                    assemblyName,                     AssemblyBuilderAccess.RunAndSave);            // 3. 定义模块(DLL 文件)            ModuleBuilder moduleBuilder =                 assemblyBuilder.DefineDynamicModule("MyDynamicAssembly", "MyDynamicAssembly.dll");            // 4. 定义一个新类型(类)            TypeBuilder typeBuilder =                 moduleBuilder.DefineType("HelloWorldClass", TypeAttributes.Public);            // 5. 定义一个方法            MethodBuilder methodBuilder =                 typeBuilder.DefineMethod(                    "SayHello",                     MethodAttributes.Public | MethodAttributes.Static,                     typeof(void),                     Type.EmptyTypes);            // 6. 生成方法体(IL 代码)            ILGenerator il = methodBuilder.GetILGenerator();            il.Emit(OpCodes.Ldstr, "Hello from dynamic assembly!");            il.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }));            il.Emit(OpCodes.Ret);            // 7. 创建类型            Type helloType = typeBuilder.CreateType();            // 8. 保存程序集到磁盘            assemblyBuilder.Save("MyDynamicAssembly.dll");            Console.WriteLine("动态程序集已成功保存为 MyDynamicAssembly.dll");            // 9. (可选)立即调用测试            var method = helloType.GetMethod("SayHello");            method.Invoke(null, null);        }    }}

关键点解析

  • AssemblyBuilderAccess.RunAndSave:这是保存动态程序集的关键。如果使用 Run 模式,则无法调用 Save() 方法。
  • DefineDynamicModule 的第二个参数指定了输出文件名。
  • 必须先调用 CreateType() 完成类型定义,才能保存程序集。

验证保存结果

运行上述程序后,你会在输出目录(如 bin\Debug)看到 MyDynamicAssembly.dll。你可以用 ILSpy、dnSpy 或 Visual Studio 打开它,查看其中是否包含 HelloWorldClassSayHello 方法。

注意事项

  • 该方法仅适用于 .NET Framework。在 .NET Core/.NET 5+ 中,Save() 方法不存在。
  • 若需跨平台支持,建议使用 Roslyn 编译器 API 动态生成 C# 源码并编译为 DLL。
  • 保存的程序集路径默认为应用程序当前工作目录。

总结

通过本文,你已经学会了如何在 C# 中使用 Reflection.Emit 创建动态程序集并将其持久化保存到磁盘。这项技术对于需要高性能代码生成的场景非常有用。记住,关键词包括:C#动态程序集动态程序集持久化C# Emit保存程序集.NET动态代码生成。掌握这些技能,将大大提升你在高级 .NET 开发中的能力!