如何从未加载的引用NuGet程序集中获取接口实现类型?
这个问题我之前也碰到过,本质是CLR的延迟加载(懒加载)机制在搞鬼,咱们一步步拆解解决:
首先说原因:.NET默认不会主动加载所有引用的程序集,只有当程序集里的类型被实际访问(比如实例化、用typeof获取类型、访问静态成员)时,CLR才会把这个程序集加载到应用域里。你之前用Assembly.GetExecutingAssembly().GetReferencedAssemblies().Select(Assembly.Load)尝试加载所有引用程序集,但对于那些从未被碰过的NuGet包程序集,CLR可能找不到它们的位置(或者说没触发加载的触发条件),而当你实例化一个包里的类型时,CLR会自动去解析并加载这个程序集,之后你的加载逻辑自然就能拿到它了。
接下来给你几个实用的解决方案,不用再靠临时实例化这种“hack”方法:
1. 轻量触发程序集加载(最简便)
不用实例化对象,只要用typeof引用目标程序集里的任意一个类型就行,这会触发CLR加载整个程序集,而且比实例化更轻量:
// 只需要引用该NuGet包中的任意一个类型,不需要创建实例 _ = typeof(SomeTypeFromThatNugetPackage); // 之后再执行你的加载逻辑 var assemblies = Assembly.GetExecutingAssembly() .GetReferencedAssemblies() .Select(Assembly.Load);
2. 批量强制加载引用程序集(更可靠)
如果有多个第三方程序集需要处理,可以遍历所有引用的程序集名称,强制加载并处理可能的加载异常(比如系统程序集或者找不到的程序集):
var executingAssembly = Assembly.GetExecutingAssembly(); var referencedAssemblyNames = executingAssembly.GetReferencedAssemblies(); var loadedAssemblies = new List<Assembly>(); foreach (var assemblyName in referencedAssemblyNames) { try { // 强制加载目标程序集 var assembly = Assembly.Load(assemblyName); loadedAssemblies.Add(assembly); } catch (FileNotFoundException) { // 跳过找不到的程序集,根据你的需求调整处理逻辑 continue; } } // 现在可以从loadedAssemblies里查找实现接口的类型了
3. .NET Core/.NET 5+ 专属:用AssemblyLoadContext精细控制
如果你用的是较新的.NET版本,可以借助AssemblyLoadContext来更灵活地管理程序集加载:
var defaultAlc = AssemblyLoadContext.Default; var executingAssembly = Assembly.GetExecutingAssembly(); foreach (var assemblyName in executingAssembly.GetReferencedAssemblies()) { try { var assembly = defaultAlc.LoadFromAssemblyName(assemblyName); // 在这里处理加载后的程序集,比如查找目标类型 } catch (FileNotFoundException) { // 按需处理异常 } }
最后补个注意事项:
- 确保你的NuGet包引用的程序集在项目属性里设置了Copy Local = True,这样程序集会被复制到输出目录,CLR才能顺利找到并加载它们。
- 不要盲目加载所有引用程序集,不必要的加载会增加内存占用和启动时间,按需加载即可。
内容的提问来源于stack exchange,提问作者Laoujin
相关产品推荐
相关产品推荐

