编辑
2025-09-17
C#
00

目录

动态类型生成:为什么需要它?
Reflection.Emit:底层动态类型创建利器
完整实例:创建动态Person类
进阶:添加方法和事件
ExpandoObject:轻量级动态对象创建
Expression Trees:函数式动态代码生成
6. 性能考量与最佳实践
6.1 性能注意事项
6.2 最佳实践
总结

在C#编程世界中,动态类型生成是一项强大而又神秘的技术。无论是开发插件系统、构建ORM框架,还是实现代码生成工具,运行时动态创建类型的能力都能让我们的应用更加灵活和强大。本文将带您深入了解C#中的动态类型生成技术,掌握这一高级开发技能。

动态类型生成:为什么需要它?

在传统的静态编译语言中,类型通常在编译时确定。但在某些场景下,我们需要在程序运行时根据外部数据或条件动态创建新的类型:

  • 数据映射:根据数据库表结构自动生成实体类
  • 代码生成:根据配置或模板动态生成代码
  • 插件系统:运行时加载和创建未知类型
  • 序列化/反序列化:处理未知的数据结构
  • 元编程:在运行时修改或扩展程序的行为

Reflection.Emit:底层动态类型创建利器

Reflection.Emit是.NET框架提供的最强大的动态类型生成工具,它允许我们在IL(中间语言)级别创建新类型。

完整实例:创建动态Person类

C#
using System.Reflection.Emit; using System.Reflection; namespace AppReflectionEmit { internal class Program { public static Type CreateDynamicType() { // 创建动态程序集 AssemblyName assemblyName = new AssemblyName("DynamicAssembly"); AssemblyBuilder assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly( assemblyName, AssemblyBuilderAccess.Run); // 创建模块 ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("DynamicModule"); // 定义类型 TypeBuilder typeBuilder = moduleBuilder.DefineType( "DynamicPerson", TypeAttributes.Public | TypeAttributes.Class); // 添加字段 FieldBuilder nameField = typeBuilder.DefineField( "_name", typeof(string), FieldAttributes.Private); // 创建构造函数 ConstructorBuilder constructorBuilder = typeBuilder.DefineConstructor( MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName, CallingConventions.Standard, new[] { typeof(string) }); // 生成构造函数的 IL 代码 ILGenerator constructorIL = constructorBuilder.GetILGenerator(); constructorIL.Emit(OpCodes.Ldarg_0); constructorIL.Emit(OpCodes.Call, typeof(object).GetConstructor(Type.EmptyTypes)); constructorIL.Emit(OpCodes.Ldarg_0); constructorIL.Emit(OpCodes.Ldarg_1); constructorIL.Emit(OpCodes.Stfld, nameField); constructorIL.Emit(OpCodes.Ret); // 添加属性 PropertyBuilder nameProperty = typeBuilder.DefineProperty( "Name", PropertyAttributes.HasDefault, typeof(string), null); // 创建 getter 方法 MethodBuilder getterMethod = typeBuilder.DefineMethod( "get_Name", MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, typeof(string), Type.EmptyTypes); ILGenerator getterIL = getterMethod.GetILGenerator(); getterIL.Emit(OpCodes.Ldarg_0); getterIL.Emit(OpCodes.Ldfld, nameField); getterIL.Emit(OpCodes.Ret); // 创建 setter 方法 MethodBuilder setterMethod = typeBuilder.DefineMethod( "set_Name", MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, null, new[] { typeof(string) }); ILGenerator setterIL = setterMethod.GetILGenerator(); setterIL.Emit(OpCodes.Ldarg_0); setterIL.Emit(OpCodes.Ldarg_1); setterIL.Emit(OpCodes.Stfld, nameField); setterIL.Emit(OpCodes.Ret); // 将方法与属性关联 nameProperty.SetGetMethod(getterMethod); nameProperty.SetSetMethod(setterMethod); // 创建最终类型 return typeBuilder.CreateType(); } static void Main(string[] args) { // 创建动态类型 Type dynamicPersonType = CreateDynamicType(); // 创建实例 object personInstance = Activator.CreateInstance(dynamicPersonType, "张三"); // 获取属性 PropertyInfo nameProperty = dynamicPersonType.GetProperty("Name"); // 读取属性值 object nameValue = nameProperty.GetValue(personInstance); Console.WriteLine($"姓名: {nameValue}"); // 输出: 姓名: 张三 // 设置新值 nameProperty.SetValue(personInstance, "张三丰"); Console.WriteLine($"修改后姓名: {nameProperty.GetValue(personInstance)}"); Console.ReadKey(); } } }

image.png

上面的代码演示了如何使用Reflection.Emit创建一个完整的动态类型。这个例子看似复杂,但它展示了以下几个关键步骤:

  1. 创建程序集和模块:动态类型需要存在于程序集中
  2. 定义类型:指定类型的名称和特性
  3. 添加字段:定义私有字段存储数据
  4. 创建构造函数:通过IL代码实现构造函数逻辑
  5. 添加属性:定义属性及其对应的getter和setter方法
  6. 创建最终类型:编译并生成可使用的类型

进阶:添加方法和事件

我们可以进一步扩展上面的示例,添加自定义方法和事件:

C#
using System.Reflection.Emit; using System.Reflection; namespace AppReflectionEmit { internal class Program { public static Type CreateDynamicType() { // 创建动态程序集 AssemblyName assemblyName = new AssemblyName("DynamicAssembly"); AssemblyBuilder assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly( assemblyName, AssemblyBuilderAccess.Run); // 创建模块 ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("DynamicModule"); // 定义类型 TypeBuilder typeBuilder = moduleBuilder.DefineType( "DynamicPerson", TypeAttributes.Public | TypeAttributes.Class); // 添加字段 FieldBuilder nameField = typeBuilder.DefineField( "_name", typeof(string), FieldAttributes.Private); // 添加事件字段 FieldBuilder eventField = typeBuilder.DefineField( "NameChangedEvent", typeof(EventHandler), FieldAttributes.Private); // 创建构造函数 ConstructorBuilder constructorBuilder = typeBuilder.DefineConstructor( MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName, CallingConventions.Standard, new[] { typeof(string) }); // 生成构造函数的 IL 代码 ILGenerator constructorIL = constructorBuilder.GetILGenerator(); constructorIL.Emit(OpCodes.Ldarg_0); constructorIL.Emit(OpCodes.Call, typeof(object).GetConstructor(Type.EmptyTypes)); constructorIL.Emit(OpCodes.Ldarg_0); constructorIL.Emit(OpCodes.Ldarg_1); constructorIL.Emit(OpCodes.Stfld, nameField); constructorIL.Emit(OpCodes.Ret); // 添加属性 PropertyBuilder nameProperty = typeBuilder.DefineProperty( "Name", PropertyAttributes.HasDefault, typeof(string), null); // 创建 getter 方法 MethodBuilder getterMethod = typeBuilder.DefineMethod( "get_Name", MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, typeof(string), Type.EmptyTypes); ILGenerator getterIL = getterMethod.GetILGenerator(); getterIL.Emit(OpCodes.Ldarg_0); getterIL.Emit(OpCodes.Ldfld, nameField); getterIL.Emit(OpCodes.Ret); // 创建 setter 方法 MethodBuilder setterMethod = typeBuilder.DefineMethod( "set_Name", MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, null, new[] { typeof(string) }); ILGenerator setterIL = setterMethod.GetILGenerator(); // 保存旧名称用于比较 Label skipEvent = setterIL.DefineLabel(); LocalBuilder oldNameLocal = setterIL.DeclareLocal(typeof(string)); setterIL.Emit(OpCodes.Ldarg_0); setterIL.Emit(OpCodes.Ldfld, nameField); setterIL.Emit(OpCodes.Stloc, oldNameLocal); // 设置新名称 setterIL.Emit(OpCodes.Ldarg_0); setterIL.Emit(OpCodes.Ldarg_1); setterIL.Emit(OpCodes.Stfld, nameField); // 触发事件 setterIL.Emit(OpCodes.Ldarg_0); setterIL.Emit(OpCodes.Ldfld, eventField); setterIL.Emit(OpCodes.Ldnull); setterIL.Emit(OpCodes.Ceq); setterIL.Emit(OpCodes.Brtrue, skipEvent); setterIL.Emit(OpCodes.Ldarg_0); setterIL.Emit(OpCodes.Ldfld, eventField); setterIL.Emit(OpCodes.Ldarg_0); setterIL.Emit(OpCodes.Ldnull); setterIL.Emit(OpCodes.Callvirt, typeof(EventHandler).GetMethod("Invoke")); setterIL.MarkLabel(skipEvent); setterIL.Emit(OpCodes.Ret); // 将方法与属性关联 nameProperty.SetGetMethod(getterMethod); nameProperty.SetSetMethod(setterMethod); // 添加自定义方法 Introduce MethodBuilder introduceMethod = typeBuilder.DefineMethod( "Introduce", MethodAttributes.Public, typeof(string), Type.EmptyTypes); ILGenerator introduceIL = introduceMethod.GetILGenerator(); // 创建字符串:"我的名字是" + Name introduceIL.Emit(OpCodes.Ldstr, "我的名字是"); introduceIL.Emit(OpCodes.Ldarg_0); introduceIL.Emit(OpCodes.Call, getterMethod); introduceIL.Emit(OpCodes.Call, typeof(string).GetMethod("Concat", new[] { typeof(string), typeof(string) })); introduceIL.Emit(OpCodes.Ret); // 添加事件 EventBuilder nameChangedEvent = typeBuilder.DefineEvent( "NameChanged", EventAttributes.None, typeof(EventHandler)); // 添加事件的 add 方法 MethodBuilder addMethod = typeBuilder.DefineMethod( "add_NameChanged", MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, null, new[] { typeof(EventHandler) }); ILGenerator addIL = addMethod.GetILGenerator(); addIL.Emit(OpCodes.Ldarg_0); addIL.Emit(OpCodes.Ldarg_0); addIL.Emit(OpCodes.Ldfld, eventField); addIL.Emit(OpCodes.Ldarg_1); addIL.Emit(OpCodes.Call, typeof(Delegate).GetMethod("Combine", new[] { typeof(Delegate), typeof(Delegate) })); addIL.Emit(OpCodes.Castclass, typeof(EventHandler)); addIL.Emit(OpCodes.Stfld, eventField); addIL.Emit(OpCodes.Ret); // 添加事件的 remove 方法 MethodBuilder removeMethod = typeBuilder.DefineMethod( "remove_NameChanged", MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, null, new[] { typeof(EventHandler) }); ILGenerator removeIL = removeMethod.GetILGenerator(); removeIL.Emit(OpCodes.Ldarg_0); removeIL.Emit(OpCodes.Ldarg_0); removeIL.Emit(OpCodes.Ldfld, eventField); removeIL.Emit(OpCodes.Ldarg_1); removeIL.Emit(OpCodes.Call, typeof(Delegate).GetMethod("Remove", new[] { typeof(Delegate), typeof(Delegate) })); removeIL.Emit(OpCodes.Castclass, typeof(EventHandler)); removeIL.Emit(OpCodes.Stfld, eventField); removeIL.Emit(OpCodes.Ret); // 将方法与事件关联 nameChangedEvent.SetAddOnMethod(addMethod); nameChangedEvent.SetRemoveOnMethod(removeMethod); // 创建最终类型 return typeBuilder.CreateType(); } static void Main(string[] args) { // 创建动态类型 Type dynamicPersonType = CreateDynamicType(); // 创建实例 object personInstance = Activator.CreateInstance(dynamicPersonType, "张三"); // 获取属性 PropertyInfo nameProperty = dynamicPersonType.GetProperty("Name"); // 添加事件处理程序 EventInfo nameChangedEvent = dynamicPersonType.GetEvent("NameChanged"); EventHandler handler = (sender, e) => Console.WriteLine("名称已更改!"); nameChangedEvent.AddEventHandler(personInstance, handler); // 读取属性值 object nameValue = nameProperty.GetValue(personInstance); Console.WriteLine($"姓名: {nameValue}"); // 调用 Introduce 方法 MethodInfo introduceMethod = dynamicPersonType.GetMethod("Introduce"); string introduction = (string)introduceMethod.Invoke(personInstance, null); Console.WriteLine(introduction); // 设置新值 (这将触发事件) nameProperty.SetValue(personInstance, "张三丰"); Console.WriteLine($"修改后姓名: {nameProperty.GetValue(personInstance)}"); // 再次调用 Introduce 方法 introduction = (string)introduceMethod.Invoke(personInstance, null); Console.WriteLine(introduction); Console.ReadKey(); } } }

image.png

ExpandoObject:轻量级动态对象创建

如果只需要简单的动态对象,而不是完整的类型定义,ExpandoObject是一个更简单的选择:

C#
using System.Reflection.Emit; using System.Reflection; using System.Dynamic; namespace AppReflectionEmit { internal class Program { static void Main(string[] args) { dynamic person = new ExpandoObject(); // 动态添加属性 person.Name = "李四"; person.Age = 30; person.Address = "北京市海淀区"; // 动态添加方法 person.Introduce = new Func<string>(() => $"大家好,我是{person.Name},今年{person.Age}岁,住在{person.Address}"); // 调用动态添加的方法 Console.WriteLine(person.Introduce()); // 输出: 大家好,我是李四,今年30岁,住在北京市海淀区 // 作为字典使用 var personDict = (IDictionary<string, object>)person; personDict["Profession"] = "软件工程师"; // 遍历所有属性 foreach (var prop in personDict) { Console.WriteLine($"{prop.Key}: {prop.Value}"); } Console.ReadKey(); } } }

image.png

ExpandoObject的优点是使用简单,无需编写IL代码,但它只能创建单个对象实例,不能定义可复用的类型。

Expression Trees:函数式动态代码生成

表达式树是C#函数式编程的强大工具,可用于创建动态委托和LINQ查询:

C#
using System.Reflection.Emit; using System.Reflection; using System.Dynamic; using System.Linq.Expressions; namespace AppReflectionEmit { internal class Program { static void Main(string[] args) { // 创建表达式参数 ParameterExpression x = Expression.Parameter(typeof(int), "x"); ParameterExpression y = Expression.Parameter(typeof(int), "y"); // 创建复杂表达式: (x * 2) + (y * y) Expression multiplyX = Expression.Multiply(x, Expression.Constant(2)); Expression squareY = Expression.Multiply(y, y); Expression body = Expression.Add(multiplyX, squareY); // 编译为强类型委托 Func<int, int, int> calculator = Expression.Lambda<Func<int, int, int>>( body, x, y ).Compile(); // 使用动态创建的委托 Console.WriteLine($"计算结果: {calculator(5, 3)}"); // 创建更复杂的条件表达式 Expression condition = Expression.GreaterThan(x, y); Expression ifTrue = Expression.Multiply(x, y); Expression ifFalse = Expression.Subtract(x, y); Expression conditional = Expression.Condition(condition, ifTrue, ifFalse); // 编译条件表达式 Func<int, int, int> conditionalCalc = Expression.Lambda<Func<int, int, int>>( conditional, x, y ).Compile(); Console.WriteLine($"x=5, y=3时: {conditionalCalc(5, 3)}"); Console.WriteLine($"x=3, y=5时: {conditionalCalc(3, 5)}"); Console.ReadKey(); } } }

image.png

表达式树的优势在于:

  1. 类型安全:编译时检查类型错误
  2. 高性能:生成的委托执行效率接近手写代码
  3. 可序列化:表达式树可以被保存和传输
  4. 动态查询:LINQ to SQL等技术的基础

6. 性能考量与最佳实践

6.1 性能注意事项

动态类型生成会带来一定的性能开销:

  1. 初始化成本高:使用Reflection.Emit创建类型需要较多CPU资源
  2. 内存使用:动态程序集会占用额外内存空间
  3. 缓存关键:频繁创建相同类型可能导致性能问题

6.2 最佳实践

C#
public class DynamicTypePerformanceDemo { // 使用缓存避免重复创建相同类型 private static readonly Dictionary<string, Type> _typeCache = new Dictionary<string, Type>(); public static Type GetOrCreateDynamicType(string typeName, List<PropertyInfo> properties) { // 创建唯一的类型键 string typeKey = $"{typeName}_{string.Join("_", properties.Select(p => $"{p.Name}_{p.PropertyType.Name}"))}"; // 检查缓存 if(_typeCache.TryGetValue(typeKey, out Type cachedType)) { return cachedType; } // 创建新类型 Type newType = CreateDynamicTypeWithProperties(typeName, properties); // 添加到缓存 _typeCache[typeKey] = newType; return newType; } private static Type CreateDynamicTypeWithProperties(string typeName, List<PropertyInfo> properties) { // 实现动态类型创建 // ... } }

总结

C#的动态类型生成技术提供了强大的元编程能力,使开发者能够构建更灵活、更强大的应用程序。虽然这些技术有一定学习曲线,但掌握它们将极大地扩展您的编程视野。

随着.NET的发展,我们可以期待更多改进:

  • Source Generators:编译时代码生成,弥补运行时生成的性能缺陷
  • 更简化的API:降低动态类型创建的复杂度
  • 跨平台兼容性:在所有.NET平台上一致支持

无论您是开发框架、库还是应用程序,动态类型生成技术都能为您的项目带来巨大价值,值得每一位C#开发者深入学习。

本文作者:技术老小子

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!