跨多个.NET程序集查找接口实现类时IsAssignableFrom返回false的问题
.NET6跨程序集反射中IsAssignableFrom返回false的原因及解决方法
问题场景
在.NET6跨多个程序集的反射场景中:
- AssemblyA引用AssemblyB
- AssemblyC引用AssemblyB,且AssemblyC中的
TestLoading类实现了AssemblyB的ILoading接口 - 调用
typeof(ILoading).IsAssignableFrom(assembly.GetType("TestLoading"))返回false,但GetType().GetInterfaces()能正确获取到ILoading接口名称,且已确认所有必要程序集已加载
代码示例
Assembly A
public class SomeFunnyClass { public static void Main(string[] args) { Assembly.LoadFrom("AssemblyB.dll"); Assembly assemblyC = Assembly.LoadFrom("AssemblyC.dll"); SomeTests(assemblyC); } public void SomeTests(Assembly assembly) { var test = assembly.GetType("TestLoading").GetInterfaces(); // 返回ILoading var test2 = typeof(ILoading).IsAssignableFrom(assembly.GetType("TestLoading")); // 返回false } }
Assembly B
public interface ILoading { void OnLoad(); }
Assembly C
public class TestLoading : ILoading { public void OnLoad(){ // 逻辑实现 } }
原因分析
核心问题是程序集重复加载导致的CLR类型标识不匹配:
- AssemblyA本身引用了AssemblyB,应用启动时CLR会自动将AssemblyB加载到应用域中。
- 手动调用
Assembly.LoadFrom("AssemblyB.dll")会再次加载同一个物理文件的AssemblyB,此时CLR会将这两个加载的AssemblyB视为不同的程序集实例(即使文件内容完全一致,加载方式或路径差异会触发这个行为)。 - 此时:
- AssemblyA中
typeof(ILoading)对应的是CLR自动加载的AssemblyB里的接口类型 - AssemblyC的
TestLoading类实现的是它自身引用的AssemblyB里的接口类型(该实例与AssemblyA手动加载的AssemblyB实例不同)
- AssemblyA中
- CLR判断类型相等的依据是类型的全名+所属程序集实例,两个不同AssemblyB实例中的
ILoading会被视为完全不同的类型,因此IsAssignableFrom返回false。而GetInterfaces()仅返回类型名称字符串,所以看起来结果正确,但底层类型实例不匹配。
解决方法
1. 移除不必要的手动加载代码
AssemblyA已经引用了AssemblyB,CLR会自动负责加载该程序集,无需手动调用Assembly.LoadFrom。移除后,AssemblyC加载时会复用已存在的AssemblyB实例,类型标识即可匹配。
修改后的Assembly A代码:
public class SomeFunnyClass { public static void Main(string[] args) { // 移除Assembly.LoadFrom("AssemblyB.dll"); Assembly assemblyC = Assembly.LoadFrom("AssemblyC.dll"); SomeTests(assemblyC); } public void SomeTests(Assembly assembly) { var testType = assembly.GetType("TestLoading"); var test = testType.GetInterfaces(); var test2 = typeof(ILoading).IsAssignableFrom(testType); // 现在返回true } }
2. 统一程序集加载方式(若必须手动加载)
如果业务场景要求手动加载程序集,优先使用Assembly.Load(按程序集名称加载)而非Assembly.LoadFrom(按文件路径加载)。Assembly.Load会先检查应用域中是否已加载同名程序集,若存在则直接复用,避免重复加载导致的类型不匹配问题。
示例替换:
// 替换Assembly.LoadFrom("AssemblyB.dll")为: Assembly.Load("AssemblyB"); // 确保AssemblyB的名称正确,且在应用搜索路径中
内容的提问来源于stack exchange,提问作者Zer0
相关产品推荐
相关产品推荐

