You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在运行时创建泛型类的具体版本(类似MakeGenericMethod)

当然可以!用反射API就能实现泛型类的运行时具体化

和你用MethodInfo.MakeGenericMethod创建特定版本的泛型方法一样,.NET提供了对应的API来生成泛型类的具体类型版本,而且生成的类型完全是非抽象的(只要你的原始泛型类本身不是抽象的),完美帮你省去那些重复到爆炸的类定义代码。

核心方法:Type.MakeGenericType

这就是实现你需求的关键API,步骤很简单:

  1. 先获取泛型基类的泛型定义Type(注意要在类型名后加N,N是泛型参数的数量,比如3个参数就是3)
  2. 传入你需要的具体类型参数,就能得到对应版本的具体类Type

举个对应你代码的例子:

// 获取泛型基类的定义
Type bonusEdibilityBase = typeof(BonusValuesToEdibility<,,>);
// 生成针对Nutrients的具体类Type
Type bonusEdibilityNutrients = bonusEdibilityBase.MakeGenericType(
    typeof(EffectsAffectsNutrients),
    typeof(NutrientProcessor.Nutrients),
    typeof(NutrientsMinMax)
);

这个bonusEdibilityNutrients就是和你手动写的BonusEdibilityFromNutrients完全等价的类型,而且它会存在于当前运行时的程序集中,完全满足你的需求。

确保生成的类型是非抽象的

只要你的原始泛型基类(比如BonusValuesToEdibility<,,>)本身不是抽象类,用MakeGenericType生成的具体类型就会是非抽象的,可以正常实例化、用于Unity ECS等场景(你说不用顾虑ECS限制,那就更没问题了)。

批量生成,彻底告别重复代码

你可以把这些逻辑封装成一个工具方法,批量处理所有需要的泛型基类和参数组合,比如:

// 工具方法:生成泛型类的具体版本
public static Type CreateConcreteGenericType(Type genericBaseType, params Type[] typeArguments)
{
    // 校验传入的类型是否是泛型定义(必须是typeof(Foo<,,>)这种形式)
    if (!genericBaseType.IsGenericTypeDefinition)
    {
        throw new ArgumentException("请传入泛型类的定义类型,比如typeof(BonusValuesToEdibility<,,>)");
    }
    return genericBaseType.MakeGenericType(typeArguments);
}

// 批量处理你的所有需求
void SetupAllConcreteTypes()
{
    // 定义所有需要处理的泛型基类
    var genericBaseClasses = new[]
    {
        typeof(BonusValuesToEdibility<,,>),
        typeof(TransferValuesConstant<,,>),
        typeof(TransferValuesPercent<,,>),
        typeof(SwaprValuesConstant<,,>),
        typeof(SwapValuesPercent<,,>),
        typeof(BonusValuesConstant<,,>),
        typeof(BonusValuesPercent<,,>)
    };

    // 定义所有需要的类型参数组合
    var typeParamSets = new[]
    {
        new[] { typeof(EffectsAffectsNutrients), typeof(NutrientProcessor.Nutrients), typeof(NutrientsMinMax) },
        new[] { typeof(EffectsAffectsTastes), typeof(TasteProcessor.Tastes), typeof(TastesMinMax) },
        new[] { typeof(EffectsAffectsAroma), typeof(AromaProcessor.Aroma), typeof(AromaMinMax) },
        new[] { typeof(EffectsAffectsComposition), typeof(CompositionProcessor.Composition), typeof(DummyMinMax2) },
        new[] { typeof(EffectsAffectsCookProperties), typeof(CookPropertiesProcessor.CookProperties), typeof(DummyMinMax1) },
        new[] { typeof(EffectsAffectsQuality), typeof(ItemInstance), typeof(QualityMinMax) }
    };

    // 遍历生成所有具体类型,还可以把它们存到字典里方便后续使用
    var concreteTypes = new Dictionary<string, Type>();
    foreach (var baseClass in genericBaseClasses)
    {
        foreach (var paramSet in typeParamSets)
        {
            var concreteType = CreateConcreteGenericType(baseClass, paramSet);
            // 生成一个唯一键,方便后续查找
            var key = $"{baseClass.Name.Split('`')[0]}_{string.Join("_", paramSet.Select(t => t.Name))}";
            concreteTypes.Add(key, concreteType);
        }
    }

    // 后续需要用的时候,直接从字典里取就行
    // 比如 var nutrientBonusType = concreteTypes["BonusValuesToEdibility_EffectsAffectsNutrients_Nutrients_NutrientsMinMax"];
}

这样一行重复的类定义都不用写,运行时自动生成所有你需要的具体类型。

额外说明

  • 这种方式完全不需要运行时编译(比如动态编译C#代码),纯用.NET反射API实现,符合你的时间限制要求。
  • 生成的类型和手动定义的类性能完全一致,不会有额外开销。
  • 要确保泛型基类的类型参数约束都被满足,否则MakeGenericType会抛出异常,比如如果基类要求某个参数必须是值类型,那你传入引用类型就会报错。
  • 如果需要实例化这些类型,可以用Activator.CreateInstance(concreteType),有构造参数的话就传对应的参数进去。

内容的提问来源于stack exchange,提问作者Guedez

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:41:03