https://www.toutiao.com/article/7470454747691074100/
AssemblyLoadContext 是 .NET Core 和 .NET 5+ 中引入的一个重要功能,用于动态加载和卸载程序集(Assemblies)。它提供了一种灵活的方式来管理程序集的生命周期,尤其是在需要动态加载插件或模块化应用程序时非常有用。
以下是 AssemblyLoadContext 的使用方式、核心概念以及常见场景的详细说明。
- 核心概念
默认上下文(Default Context):
所有程序集在没有显式指定 AssemblyLoadContext 的情况下,默认会被加载到默认上下文中。
默认上下文中的程序集无法卸载。
自定义上下文(Custom Context):
开发者可以创建自定义的 AssemblyLoadContext,用于隔离加载的程序集。
自定义上下文中的程序集可以通过释放上下文来卸载。
程序集卸载:
在 .NET Framework 中,程序集一旦加载就无法卸载。而在 .NET Core 和 .NET 5+ 中,通过 AssemblyLoadContext 可以实现程序集的卸载。 - 使用方式
2.1 创建自定义AssemblyLoadContext
以下是一个简单的示例,展示如何创建一个自定义的 AssemblyLoadContext 并加载程序集:
using System;
using System.IO;
using System.Reflection;
using System.Runtime.Loader;
public class CustomAssemblyLoadContext : AssemblyLoadContext
{
public CustomAssemblyLoadContext() : base(isCollectible: true)
{
// isCollectible 设置为 true 表示该上下文是可收集的(即支持卸载)
}
protected override Assembly Load(AssemblyName assemblyName)
{
// 如果需要自定义加载逻辑,可以在这里实现
return null; // 返回 null 表示使用默认加载逻辑
}
}
class Program
{
static void Main(string[] args)
{
// 创建自定义上下文
var customLoadContext = new CustomAssemblyLoadContext();
// 加载程序集
string assemblyPath = Path.Combine(AppContext.BaseDirectory, "MyPlugin.dll");
Assembly assembly = customLoadContext.LoadFromAssemblyPath(assemblyPath);
// 获取类型并调用方法
Type type = assembly.GetType("MyPlugin.MyClass");
object instance = Activator.CreateInstance(type);
MethodInfo method = type.GetMethod("SayHello");
method.Invoke(instance, null);
// 卸载上下文
customLoadContext.Unload();
Console.WriteLine("Assembly unloaded.");
}
}
2.2 动态加载和卸载程序集
以下是一个更完整的示例,展示如何动态加载和卸载程序集:
using System;
using System.IO;
using System.Reflection;
using System.Runtime.Loader;
using System.Threading;
public class PluginLoader : IDisposable
{
private AssemblyLoadContext _context;
public PluginLoader()
{
_context = new AssemblyLoadContext("PluginContext", isCollectible: true);
}
public void LoadAndRunPlugin(string assemblyPath)
{
// 加载程序集
Assembly assembly = _context.LoadFromAssemblyPath(assemblyPath);
// 获取类型并调用方法
Type type = assembly.GetType("MyPlugin.MyClass");
if (type != null)
{
object instance = Activator.CreateInstance(type);
MethodInfo method = type.GetMethod("SayHello");
method?.Invoke(instance, null);
}
}
public void Unload()
{
_context.Unload();
GC.Collect();
GC.WaitForPendingFinalizers();
}
public void Dispose()
{
Unload();
}
}
class Program
{
static void Main(string[] args)
{
string pluginPath = Path.Combine(AppContext.BaseDirectory, "MyPlugin.dll");
using (var loader = new PluginLoader())
{
loader.LoadAndRunPlugin(pluginPath);
}
Console.WriteLine("Plugin unloaded.");
}
}
- 常见场景
3.1 插件系统
使用 AssemblyLoadContext 可以实现动态加载和卸载插件,而不会影响主应用程序的运行。
示例:一个应用程序支持多个插件,每个插件都独立加载到自己的 AssemblyLoadContext 中。
3.2 热更新
在某些场景下,可能需要在不重启应用程序的情况下更新某些模块。通过 AssemblyLoadContext,可以卸载旧版本的程序集并加载新版本。
3.3 隔离加载
如果需要加载不受信任的代码(如第三方库),可以将其加载到独立的 AssemblyLoadContext 中,以避免对主应用程序的影响。 - 注意事项
4.1 程序集卸载的限制
即使调用了 Unload() 方法,程序集并不会立即被卸载。只有在垃圾回收器运行并且没有任何引用指向该上下文时,程序集才会被真正卸载。
因此,建议在调用 Unload() 后手动触发垃圾回收:
GC.Collect(); GC.WaitForPendingFinalizers();
4.2 避免跨上下文引用
不要在不同上下文之间共享对象实例。如果一个对象是从某个上下文中加载的,则不应在另一个上下文中使用它。
4.3 性能开销
动态加载和卸载程序集会带来一定的性能开销,因此应谨慎使用,尤其是在高频场景中。 - 总结
AssemblyLoadContext 提供了强大的功能,允许开发者动态加载和卸载程序集,从而实现插件系统、热更新和隔离加载等高级功能。然而,在使用时需要注意其限制和潜在的性能问题。
文档更新时间: 2025-02-13 08:54 作者:admin