动态加载类型时Type.GetConstructor(带参数类型)调用失败问题排查
插件加载反射异常问题解析
用户问题描述
初始问题
通过AssemblyLoadContext.LoadFromAssemblyName按官方插件开发流程加载插件:
- 插件程序集加载正常,可定位到实现指定接口的类型
- 能通过
Activator.CreateInstance实例化目标类型的无参构造函数 - 调用
Type.GetConstructor获取带特定参数(如ILogger)的构造函数时返回null,但调试确认该构造函数存在 - 静态加载同一类型时,
Type.GetConstructor调用成功
更新后问题
将ILogger参数从构造函数移至接口声明的方法后:
- 调用
Assembly.GetTypes(经RuntimeModule.GetTypes触发)抛出ReflectionTypeLoadException - 错误信息显示:“程序集‘blah’中类型‘blah’的方法‘blah’未实现”
- 涉事方法正是带
ILogger参数的接口方法,移除该参数后异常消失,疑似运行时无法识别主程序与插件中的ILogger为同一类型
核心原因
问题根源是**.NET AssemblyLoadContext的类型隔离机制**:
- CLR判定类型唯一性的依据不仅是类型全名、程序集信息,还包含加载该类型的
AssemblyLoadContext实例。即使是完全相同的类型,被不同上下文加载后,会被视为两个毫无关联的类型。 - 初始问题中,主程序的
ILogger类型与插件程序集引用的ILogger分属不同上下文,用主程序的ILogger类型作为参数查找构造函数时,CLR判定参数类型不匹配,因此返回null。 - 更新后的问题里,接口定义的方法参数是主程序上下文的
ILogger,但插件实现时使用的是自身上下文加载的ILogger,CLR认为插件类型未正确实现接口方法,进而抛出ReflectionTypeLoadException。
解决建议
- 共享类型统一加载:将
ILogger、插件接口等需要跨主程序与插件共享的类型,提取到独立的类库中。主程序和插件均引用该类库,且确保AssemblyLoadContext加载共享类库时,复用主程序已加载的版本(可通过LoadFromAssemblyName自动复用,或在自定义AssemblyLoadContext中重写Load方法,优先从主上下文加载共享程序集)。 - 避免跨上下文类型传递:如果必须在主程序与插件间传递对象,可让共享类型继承
MarshalByRefObject,实现跨上下文的对象访问。
内容的提问来源于stack exchange,提问作者Ian Horwill
相关产品推荐
相关产品推荐

