如何通过基类继承时传入的ID参数查找对应类型?
解决方案
核心思路
通过反射筛选所有继承自BaseModel的类,提取每个类构造时传递给基类的id参数值,建立id与类型的映射关系,后续即可通过id快速查找对应类型。
实现方案
方案一:解析构造函数IL提取id(适用于硬编码常量id)
如果id是编译时硬编码的常量字符串,可以读取构造函数的IL指令来提取:
- 筛选继承类
var targetAssembly = Assembly.GetExecutingAssembly(); // 替换为你已获取的程序集 var baseModelType = typeof(BaseModel); // 筛选所有非抽象的BaseModel子类 var derivedTypes = targetAssembly.GetTypes() .Where(t => t.IsClass && !t.IsAbstract && baseModelType.IsAssignableFrom(t));
- 提取id值
编写方法解析构造函数IL,提取传入基类的id参数:
private static string? ExtractModelId(Type modelType) { // 获取目标构造函数(假设子类只有一个接收Provider参数的构造函数) var constructor = modelType.GetConstructors(BindingFlags.Public | BindingFlags.Instance) .FirstOrDefault(c => c.GetParameters().Length == 1 && c.GetParameters()[0].ParameterType == typeof(Provider)); if (constructor?.GetMethodBody()?.GetILAsByteArray() is not byte[] ilBytes) return null; // 遍历IL指令,查找ldstr(加载字符串常量)指令 int index = 0; while (index < ilBytes.Length) { if (ilBytes[index] == 0x72) // ldstr指令的操作码 { // 读取字符串的元数据token,解析出字符串内容 int stringToken = BitConverter.ToInt32(ilBytes, index + 1); return modelType.Module.ResolveString(stringToken); } // 跳过当前指令,处理下一个 index += GetILInstructionLength(ilBytes, index); } return null; } // 简单计算IL指令长度(仅处理本场景需要的指令) private static int GetILInstructionLength(byte[] ilBytes, int index) { byte opCode = ilBytes[index]; // 单字节指令(无操作数)长度为1 if (opCode is >= 0x00 and <= 0x1F) return 1; // 带4字节操作数的指令(如ldstr)长度为5 if (opCode is >= 0x20 and <= 0x7F) return 5; // 其他情况默认长度为1(可根据实际需求扩展) return 1; }
- 建立映射并查找
// 构建id到类型的映射字典 var idTypeMap = derivedTypes.ToDictionary( type => ExtractModelId(type), type => type, StringComparer.OrdinalIgnoreCase ); // 通过id查找类型 string targetId = "model-1"; if (idTypeMap.TryGetValue(targetId, out var matchedType)) { Console.WriteLine($"找到对应类型:{matchedType.FullName}"); } else { Console.WriteLine($"未找到id为{targetId}的类型"); }
方案二:使用特性标记(更可靠易维护)
如果可以修改代码,推荐给每个子类添加自定义特性标记id,这种方式比解析IL更稳定:
- 定义特性
[AttributeUsage(AttributeTargets.Class, Inherited = false)] public class ModelIdAttribute : Attribute { public string Id { get; } public ModelIdAttribute(string id) => Id = id; }
- 标记子类
[ModelId("model-1")] public class Model1(Provider provider) : BaseModel(provider, id: "model-1"); [ModelId("model-2")] public class Model2(Provider provider) : BaseModel(provider, id: "model-2");
- 提取id并建立映射
private static string? GetModelIdFromAttribute(Type modelType) { return modelType.GetCustomAttribute<ModelIdAttribute>()?.Id; } // 构建映射字典 var idTypeMap = derivedTypes.ToDictionary( type => GetModelIdFromAttribute(type), type => type, StringComparer.OrdinalIgnoreCase ); // 查找逻辑同方案一
注意事项
- 方案一仅适用于
id是编译时常量的场景,如果id是动态计算的(如传入变量),此方法无效。 - 若子类存在多个构造函数,需要调整构造函数筛选逻辑,确保找到正确调用基类构造的那个。
- 建议缓存
idTypeMap字典,避免每次查找都重新解析,提升性能。
内容的提问来源于stack exchange,提问作者CurlyFro
相关产品推荐
相关产品推荐

