如何在运行时创建泛型类的具体版本(类似MakeGenericMethod)
当然可以!用反射API就能实现泛型类的运行时具体化
和你用MethodInfo.MakeGenericMethod创建特定版本的泛型方法一样,.NET提供了对应的API来生成泛型类的具体类型版本,而且生成的类型完全是非抽象的(只要你的原始泛型类本身不是抽象的),完美帮你省去那些重复到爆炸的类定义代码。
核心方法:Type.MakeGenericType
这就是实现你需求的关键API,步骤很简单:
- 先获取泛型基类的泛型定义Type(注意要在类型名后加
N,N是泛型参数的数量,比如3个参数就是3) - 传入你需要的具体类型参数,就能得到对应版本的具体类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
相关产品推荐
相关产品推荐

