如何用System.Reflection.Emit从T派生类型?Build方法实现疑问求解
嘿,我来帮你搞定这两个问题,一步步搭建你的动态增强框架!下面分两部分拆解:
要动态生成继承自T的子类,核心是利用Reflection.Emit的类型构建API,步骤很清晰:
创建动态程序集和模块
首先得定义一个内存中的临时程序集,再在里面创建模块——这是生成动态类型的容器:var assemblyName = new AssemblyName($"DynamicEnhancers_{typeof(T).Name}"); AssemblyBuilder asmBuilder = AssemblyBuilder.DefineDynamicAssembly( assemblyName, AssemblyBuilderAccess.Run); // Run表示仅在内存中运行,不保存到磁盘 ModuleBuilder modBuilder = asmBuilder.DefineDynamicModule($"{assemblyName.Name}.dll");定义派生类型
用TypeBuilder创建一个继承自T的类,给它起个辨识度高的名字(比如Enhanced{TypeName}):TypeBuilder typeBuilder = modBuilder.DefineType( $"Enhanced{typeof(T).Name}", TypeAttributes.Public | TypeAttributes.Class, typeof(T)); // 指定父类为目标类型T添加增强逻辑
这一步是给子类注入额外功能的核心,比如给方法加日志、拦截调用,或者给属性加校验。举个例子,假设T有一个GetPrice()方法,我们重写它并添加日志逻辑:// 获取基类的GetPrice方法 MethodInfo baseMethod = typeof(T).GetMethod("GetPrice", Type.EmptyTypes); if (baseMethod != null) { // 定义重写的方法,签名和基类完全一致 MethodBuilder methodBuilder = typeBuilder.DefineMethod( "GetPrice", MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig, baseMethod.ReturnType, Type.EmptyTypes); ILGenerator il = methodBuilder.GetILGenerator(); // 先插入日志逻辑 il.EmitWriteLine($"[Enhanced] Calling {typeof(T).Name}.GetPrice()"); // 调用基类的GetPrice方法 il.Emit(OpCodes.Call, baseMethod); // 返回结果 il.Emit(OpCodes.Ret); // 标记该方法为对基类方法的重写 typeBuilder.DefineMethodOverride(methodBuilder, baseMethod); }完成类型创建
最后调用CreateType()完成动态类型的生成,得到我们的增强子类:Type enhancedType = typeBuilder.CreateType();
要让Enhancer.Build<Stock>("Apple", "Dow Jones...")把参数正确传给Stock的构造函数,关键是在动态生成子类时,定义和基类构造函数签名匹配的子类构造函数,并在内部调用基类构造函数。
第一步:在动态类型中生成匹配的构造函数
我们可以遍历基类的所有公共构造函数,为每个构造函数生成对应的子类构造函数,确保参数能正确传递:
// 遍历基类的所有公共实例构造函数 foreach (var baseCtor in typeof(T).GetConstructors(BindingFlags.Public | BindingFlags.Instance)) { var paramTypes = baseCtor.GetParameters().Select(p => p.ParameterType).ToArray(); // 定义子类构造函数,签名和基类一致 ConstructorBuilder ctorBuilder = typeBuilder.DefineConstructor( MethodAttributes.Public, baseCtor.CallingConvention, paramTypes); ILGenerator il = ctorBuilder.GetILGenerator(); // 加载this指针 il.Emit(OpCodes.Ldarg_0); // 依次加载所有构造参数(参数从arg_1开始) for (int i = 0; i < paramTypes.Length; i++) { il.Emit(OpCodes.Ldarg, i + 1); } // 调用基类构造函数 il.Emit(OpCodes.Call, baseCtor); // 返回 il.Emit(OpCodes.Ret); }
第二步:封装Enhancer.Build方法
把上面的逻辑封装到Enhancer类里,再加个缓存避免重复生成相同类型,提升性能:
public static class Enhancer { // 缓存已生成的增强类型,避免重复生成 private static readonly Dictionary<Type, Type> _enhancedTypeCache = new Dictionary<Type, Type>(); public static T Build<T>(params object[] args) { Type baseType = typeof(T); // 先查缓存,没有再生成 if (!_enhancedTypeCache.TryGetValue(baseType, out Type enhancedType)) { enhancedType = CreateEnhancedType<T>(); _enhancedTypeCache[baseType] = enhancedType; } // 根据传入的参数,调用增强类型的构造函数实例化 return (T)Activator.CreateInstance(enhancedType, args); } private static Type CreateEnhancedType<T>() { Type baseType = typeof(T); var assemblyName = new AssemblyName($"DynamicEnhancers_{baseType.Name}"); AssemblyBuilder asmBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run); ModuleBuilder modBuilder = asmBuilder.DefineDynamicModule($"{assemblyName.Name}.dll"); // 定义派生类型 TypeBuilder typeBuilder = modBuilder.DefineType( $"Enhanced{baseType.Name}", TypeAttributes.Public | TypeAttributes.Class, baseType); // --- 这里可以添加你需要的增强逻辑(比如前面的方法重写、属性校验等)--- // 生成匹配基类的构造函数 foreach (var baseCtor in baseType.GetConstructors(BindingFlags.Public | BindingFlags.Instance)) { var paramTypes = baseCtor.GetParameters().Select(p => p.ParameterType).ToArray(); ConstructorBuilder ctorBuilder = typeBuilder.DefineConstructor( MethodAttributes.Public, baseCtor.CallingConvention, paramTypes); ILGenerator il = ctorBuilder.GetILGenerator(); il.Emit(OpCodes.Ldarg_0); for (int i = 0; i < paramTypes.Length; i++) { il.Emit(OpCodes.Ldarg, i + 1); } il.Emit(OpCodes.Call, baseCtor); il.Emit(OpCodes.Ret); } // 完成类型生成 return typeBuilder.CreateType(); } }
测试示例
假设你的Stock类是这样的:
public class Stock { public string Name { get; } public string Market { get; } public Stock(string name, string market) { Name = name; Market = market; } public virtual decimal GetPrice() { // 模拟获取价格 return 150.5m; } }
调用var appleStock = Enhancer.Build<Stock>("Apple", "Dow Jones...");,就能得到一个增强版的Stock实例——它不仅会用传入的参数完成基类构造,还能拥有你在CreateEnhancedType里添加的任何额外功能。
内容的提问来源于stack exchange,提问作者MigthyMoron




