You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多
文档控制台
免费开始使用

如何用System.Reflection.Emit从T派生类型?Build方法实现疑问求解

嘿,我来帮你搞定这两个问题,一步步搭建你的动态增强框架!下面分两部分拆解:

一、用System.Reflection.Emit从类型T派生出新类型

要动态生成继承自T的子类,核心是利用Reflection.Emit的类型构建API,步骤很清晰:

  1. 创建动态程序集和模块
    首先得定义一个内存中的临时程序集,再在里面创建模块——这是生成动态类型的容器:

    var assemblyName = new AssemblyName($"DynamicEnhancers_{typeof(T).Name}");
    AssemblyBuilder asmBuilder = AssemblyBuilder.DefineDynamicAssembly(
        assemblyName, 
        AssemblyBuilderAccess.Run); // Run表示仅在内存中运行,不保存到磁盘
    ModuleBuilder modBuilder = asmBuilder.DefineDynamicModule($"{assemblyName.Name}.dll");
    
  2. 定义派生类型
    TypeBuilder创建一个继承自T的类,给它起个辨识度高的名字(比如Enhanced{TypeName}):

    TypeBuilder typeBuilder = modBuilder.DefineType(
        $"Enhanced{typeof(T).Name}",
        TypeAttributes.Public | TypeAttributes.Class,
        typeof(T)); // 指定父类为目标类型T
    
  3. 添加增强逻辑
    这一步是给子类注入额外功能的核心,比如给方法加日志、拦截调用,或者给属性加校验。举个例子,假设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);
    }
    
  4. 完成类型创建
    最后调用CreateType()完成动态类型的生成,得到我们的增强子类:

    Type enhancedType = typeBuilder.CreateType();
    
二、实现Enhancer.Build方法,传递参数给基类构造函数

要让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

火山引擎 最新活动