C#如何根据Args实例类型动态创建对应GenericClass泛型实现类实例
实现方案
核心思路是程序启动时一次性扫描程序集构建Args类型到对应实现类的映射缓存,既不用手动维护映射关系,也不会每次调用都遍历类,性能无额外损耗。
第一步:构建全局映射缓存
用静态构造函数实现扫描和缓存,仅执行一次:
using System.Reflection; using System.Collections.Generic; using System.Linq; // 你的包含CreateSpecificInstance方法的类 public class InstanceFactory { // 缓存:Key是Args类型,Value是对应的实现类类型 private static readonly IReadOnlyDictionary<Type, Type> _argsToImplMap; // 静态构造函数:程序首次使用InstanceFactory时自动执行,仅跑一次 static InstanceFactory() { var openGenericBase = typeof(GenericClass<>); // 按需调整要扫描的程序集,这里默认扫当前程序集,多程序集的话可以传入Assembly数组 var allCandidateTypes = Assembly.GetExecutingAssembly() .GetTypes() // 只筛选非抽象的普通类,排除无关类型 .Where(t => t.IsClass && !t.IsAbstract); var map = new Dictionary<Type, Type>(); foreach (var type in allCandidateTypes) { var baseType = type.BaseType; // 向上查找父类,匹配是否继承自GenericClass<>的闭合泛型类型 while (baseType != null && baseType.IsGenericType) { if (baseType.GetGenericTypeDefinition() == openGenericBase) { // 取出泛型参数即对应的Args类型 var argsType = baseType.GetGenericArguments()[0]; map[argsType] = type; break; } baseType = baseType.BaseType; } } _argsToImplMap = map; }
第二步:实现实例创建方法
public object CreateSpecificInstance(ArgsBaseClass args) { if (args == null) throw new ArgumentNullException(nameof(args)); var argsType = args.GetType(); if (!_argsToImplMap.TryGetValue(argsType, out var implType)) { throw new KeyNotFoundException($"未找到对应{argsType.Name}的GenericClass实现类"); } // 直接创建实现类实例,传入args参数 return Activator.CreateInstance(implType, args); } }
优化建议
- 如果需要统一调用实例的方法,可以给
GenericClass<TArgs>加一个协变非泛型接口/基类,这样返回值可以直接转成接口类型使用,不需要处理动态类型:// 定义非泛型基类或者协变接口 public interface IGenericHandler { void Execute(); } abstract class GenericClass<TArgs> : IGenericHandler where TArgs : ArgsBaseClass { public abstract void Execute(); } // 调用时直接转成接口即可 public IGenericHandler CreateSpecificInstance(ArgsBaseClass args) { // 前面逻辑不变 return (IGenericHandler)Activator.CreateInstance(implType, args); } - 如果实现类分散在多个程序集,只需要修改
Assembly.GetExecutingAssembly()部分,传入所有要扫描的程序集即可。 - 要是扫描范围太大性能不满意,可以给所有实现类加自定义
[ArgsImplAttribute],扫描时先筛选带该Attribute的类即可。
原有代码问题修正
你之前写的typeof(args)是语法错误,typeof只能传入类型标识符,获取实例的运行时类型需要调用args.GetType();另外GenericClass是抽象类,不能直接用Activator.CreateInstance实例化,所以不需要先创建泛型基类的实例,直接创建找到的实现类实例即可。
内容的提问来源于stack exchange,提问作者Leander
相关产品推荐
相关产品推荐

