You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

动态加载类型时强制转换抛出InvalidCastException异常的问题求助

问题分析与解决

核心原因

你遇到的问题是同一个物理DLL被CLR加载了两次,生成了两个独立的程序集实例。即使类型的名称、版本、签名完全一致,CLR会认为它们是不同的类型——因为类型的唯一性由其所属的程序集实例+类型全名共同决定。

你的代码里用Assembly.LoadFile加载了当前执行程序集的物理文件,而当前程序集已经被CLR加载过一次了,这就导致了两个相同但独立的程序集实例,所以:

  • componentType == typeof(Component)输出False
  • 强制转换时抛出InvalidCastException,因为两个Component类型分属不同程序集实例
  • DI单例失效,因为容器会把这两个不同类型当成不同的服务,分别创建实例

解决方案

1. 避免重复加载同一程序集

如果是加载当前已运行的程序集,直接用Assembly.GetExecutingAssembly()即可,不需要再调用LoadFile:

class Program
{
    static void Main()
    {
        Assembly assembly = Assembly.GetExecutingAssembly();
        var componentType = assembly.GetExportedTypes().FirstOrDefault(x => x.Name == "Component");

        Console.WriteLine(componentType == typeof(Component)); // 现在会输出True

        ConstructorInfo constructor = componentType.GetConstructors()[0];
        var component = constructor.Invoke(new object[0]);

        var k = (Component)component; // 强制转换成功
    }
}

2. 跨动态加载DLL的DI场景处理

如果是加载外部DLL(而非当前程序集),需要确保共享类型只被加载一次:

  • 抽离共享契约:把需要跨程序集共享的类型(比如DI服务的接口、实体类)放到单独的类库项目(如MyApp.Contracts),主程序和所有动态加载的DLL都引用这个类库。
  • 使用正确的加载方法:
    • 优先用Assembly.Load加载程序集(通过程序集全名),CLR会自动检查缓存,避免重复加载相同标识的程序集。
    • 如果必须用路径加载,使用Assembly.LoadFrom,它也会检查当前AppDomain中是否已加载相同路径的程序集,避免重复加载。
  • 预检查已加载的程序集:加载前先遍历AppDomain.CurrentDomain.GetAssemblies(),如果目标程序集已存在,直接复用,不重复加载:
string dllPath = @"C:\Path\To\Your\External.dll";
var existingAssembly = AppDomain.CurrentDomain.GetAssemblies()
    .FirstOrDefault(a => a.Location.Equals(dllPath, StringComparison.OrdinalIgnoreCase));

Assembly assembly = existingAssembly ?? Assembly.LoadFrom(dllPath);

3. DI单例修复

确保DI容器注册和解析时,使用的是同一个程序集实例中的类型:

  • 注册服务时,用动态加载得到的类型或者共享契约类型
  • 解析时,同样使用一致的类型标识,避免因为程序集重复加载导致类型不匹配

内容的提问来源于stack exchange,提问作者markt

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 12:22:51