.NET Core/.NET 5+ 中应使用可卸载的 AssemblyLoadContext(isCollectible: true)替代不可卸载的 Assembly.LoadFrom;需重写 Load 方法、显式调用 Unload、配合 AssemblyDependencyResolver 解析依赖,并注意类型可见性与动态程序集限制。
在 .NET Core 及更高版本中,Assembly.LoadFrom 会把程序集加载进默认上下文,无法卸载,容易造成内存泄漏。真正可卸载的动态加载必须用 AssemblyLoadContext。
关键点:
AssemblyLoadContext 并重写 Load 方法,控制依赖解析逻辑isCollectible: true,否则仍不可卸载context.Unload(),且需确保无任何托管引用残留(包括事件订阅、静态字段、委托缓存)var context = new AssemblyLoadContext(isCollectible: true);
try
{
var asm = context.LoadFromAssemblyPath(@"C:\plugins\MyPlugin.dll");
// 使用 asm 创建类型实例等...
}
finally
{
context.Unload(); // 必须调用,但可能阻塞直到 GC 回收完成
}
在 .NET Framework 中最常用但不可卸载如果你还在用 .NET Framework(如 4.8),Assembly.LoadFrom 是最直接的方式,但它会把程序集加载进 Default 上下文,整个进程生命周期内无法释放。
常见误用:
LoadFrom 同一路径 → 抛出 FileLoadException:“不能为同一个程序集加载多个版本”AppDomain.Unload 卸载 → .NET Framework 中仅对非默认 AppDomain 有效,且已标记为过时try
{
var asm = Assembly.LoadFrom(@"C:\legacy\Tool.dll");
var type = asm.GetType("Tool.Processor");
var inst = Activator.CreateInstance(type);
}
catch (FileLoadException ex) when (ex.Message.Contains("same assembly"))
{
// 已加载,从 AppDomain.CurrentDomain.GetAssemblies() 查找复用
}
动态加载的程序集若依赖其他 DLL(比如 Newtonsoft.Json 或自定义基础库),不处理依赖会导致运行时报 MissingMethodException 或 FileNotFoundException。
AssemblyDependencyResolver 能自动读取 .deps.json 文件(发布时生成),定位依赖路径:
dotnet publish 输出的AssemblyLoadContext 的 Load 方法使用,否则依赖仍会 fallback 到默认上下文var resolver = new AssemblyDependencyResolver(assemblyPath); // 注意:传的是 MyPlugin.deps.json 同级的主程序集路径 var context = new CustomLoadContext(resolver); // 自定义 Load 方法中调用 resolver.ResolveAssemblyToPath(...)
动态加载后,即使 Assembly 对象存在,也可能因以下原因导致 GetType 返回 null 或 Activator.CreateInstance 失败:
asm.IsDynamic 为 true → 说明是 AssemblyBuilder 生成的动态程序集,不能用 LoadFrom 加载方式获取internal 且未用 [InternalsVisibleTo] 开放给调用方程序集GetType("Name") 写法不完整(应为 "NS.Outer+Inner`1[[T]]")建议先遍历 asm.GetTypes() 确认类型是否存在,再用 BindingFlags.NonPublic | BindingFlags.Public 获取构造器。