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

C#动态程序集的生成(Reflection.Emit入门与实战指南)

在C#开发中,C#动态程序集 是一个强大但常被忽视的功能。通过 .NET 提供的 Reflection.Emit 命名空间,我们可以在运行时动态创建类型、方法甚至整个程序集。这种能力在构建高性能 ORM、动态代理、脚本引擎或 AOP 框架时非常有用。

本教程将带你从零开始,使用 Reflection.Emit教程 的方式,一步步创建一个简单的动态程序集,并执行其中的方法。即使你是编程小白,也能轻松上手!

C#动态程序集的生成(Reflection.Emit入门与实战指南) C#动态程序集  Reflection.Emit教程 动态代码生成 C#反射编程 第1张

什么是 Reflection.Emit?

System.Reflection.Emit 是 .NET 提供的一组类,允许你在运行时动态生成 MSIL(Microsoft Intermediate Language)代码,并将其编译为可执行的方法或类型。这比传统的反射(仅读取元数据)更进一步——你不仅能“看”代码,还能“写”代码!

第一步:创建动态程序集

我们首先需要创建一个动态程序集(Dynamic Assembly)。这就像在内存中新建一个 .dll 文件,但不会写入磁盘。

using System;using System.Reflection;using System.Reflection.Emit;class Program{    static void Main()    {        // 1. 定义程序集名称        var assemblyName = new AssemblyName("MyDynamicAssembly");        // 2. 创建动态程序集(仅在内存中)        var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(            assemblyName,            AssemblyBuilderAccess.Run        );        // 3. 在程序集中定义一个模块        var moduleBuilder = assemblyBuilder.DefineDynamicModule("MainModule");        Console.WriteLine("动态程序集已创建!");    }}

第二步:定义动态类型和方法

接下来,我们在模块中定义一个名为 Calculator 的类,并添加一个静态方法 Add(int a, int b),它返回两个整数的和。

// 在 moduleBuilder 后继续// 4. 定义一个公共类 Calculatorvar typeBuilder = moduleBuilder.DefineType(    "Calculator",    TypeAttributes.Public);// 5. 定义 Add 方法:public static int Add(int a, int b)var methodBuilder = typeBuilder.DefineMethod(    "Add",    MethodAttributes.Public | MethodAttributes.Static,    typeof(int),    new Type[] { typeof(int), typeof(int) });// 6. 获取 IL 生成器,用于写入 MSIL 指令var il = methodBuilder.GetILGenerator();// 7. 编写 IL 代码:加载参数、相加、返回il.Emit(OpCodes.Ldarg_0); // 加载第一个参数 (a)il.Emit(OpCodes.Ldarg_1); // 加载第二个参数 (b)il.Emit(OpCodes.Add);     // 执行加法il.Emit(OpCodes.Ret);     // 返回结果// 8. 创建类型(完成定义)var calculatorType = typeBuilder.CreateType();

第三步:调用动态生成的方法

现在,我们可以使用反射来调用这个动态生成的 Add 方法:

// 9. 获取 Add 方法var addMethod = calculatorType.GetMethod("Add");// 10. 调用方法(因为是静态方法,第一个参数为 null)object result = addMethod.Invoke(null, new object[] { 10, 20 });Console.WriteLine($"10 + 20 = {result}"); // 输出:10 + 20 = 30

完整代码示例

以下是完整的可运行代码:

using System;using System.Reflection;using System.Reflection.Emit;class Program{    static void Main()    {        var assemblyName = new AssemblyName("MyDynamicAssembly");        var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(            assemblyName, AssemblyBuilderAccess.Run);        var moduleBuilder = assemblyBuilder.DefineDynamicModule("MainModule");        var typeBuilder = moduleBuilder.DefineType("Calculator", TypeAttributes.Public);        var methodBuilder = typeBuilder.DefineMethod(            "Add",            MethodAttributes.Public | MethodAttributes.Static,            typeof(int),            new Type[] { typeof(int), typeof(int) }        );        var il = methodBuilder.GetILGenerator();        il.Emit(OpCodes.Ldarg_0);        il.Emit(OpCodes.Ldarg_1);        il.Emit(OpCodes.Add);        il.Emit(OpCodes.Ret);        var calculatorType = typeBuilder.CreateType();        var addMethod = calculatorType.GetMethod("Add");        object result = addMethod.Invoke(null, new object[] { 10, 20 });        Console.WriteLine($"10 + 20 = {result}");    }}

应用场景与注意事项

这种 动态代码生成 技术非常适合以下场景:

  • 高性能对象映射(如 AutoMapper 内部优化)
  • 动态代理(如 Castle DynamicProxy)
  • 运行时表达式编译(如 LINQ 表达式树编译)
  • 插件系统或脚本引擎

但请注意:

  • MSIL 指令需要对底层有一定了解,错误的指令会导致运行时崩溃
  • 调试困难,建议配合单元测试使用
  • 在 .NET Core / .NET 5+ 中,部分 API 有变化,请查阅官方文档

结语

通过本篇 C#反射编程 教程,你已经掌握了如何使用 Reflection.Emit 动态生成程序集、类型和方法。虽然这项技术有一定门槛,但一旦掌握,将极大提升你在高级 C# 开发中的能力。

希望这篇关于 C#动态程序集 的入门教程对你有所帮助!动手试试吧,你会发现 .NET 的世界远比想象中更强大。