从 .Net Core 3.0开始支持程序集的加载和卸载,在 .Net FrameWork中使用独立的应用程序域来实现同样的功能,.Net Core 不支持创建多个应用程序域,所以无法使用多个应用程序域来实现程序集动态加载和卸载。
AssemblyLoadContext
程序集加载上下文,它代表一个程序集加载域,在这个域中可以加载、解析、卸载程序集
创建一个 .Net 库项目
cs
public class Class1
{
public void Fn1()
{
Console.WriteLine("Fn1");
}
public void Fn2()
{
Console.WriteLine("Fn2");
}
}
创建一个控制台项目
实现一个自定义程序集加载上下文类, isCollectible 表示是否支持程序集卸载,默认是 false,所以需要从 AssemblyLoadContext 继承并实现一个AssemblyLoadContext。
cs
internal class MyAssemblyContext:AssemblyLoadContext
{
public MyAssemblyContext() : base(isCollectible: true)
{ }
}
测试加载和卸载方法
cs
//告诉编译器不要内联该方法,防止栈上存在引用导致无法UnLoad。
[MethodImpl(MethodImplOptions.NoInlining)]
static void CallLib(string assemblyPath, out WeakReference alcWeakRef)
{
MyAssemblyContext mlc = new MyAssemblyContext();
//加载 assemblyPath 程序集到 MyAssemblyContext 上下文中
Assembly clib = mlc.LoadFromAssemblyPath(assemblyPath);
//引用 程序集加载上下文,用于确认当UnLoad时,上下文被正确清理掉了。
alcWeakRef = new WeakReference(mlc, trackResurrection: true);
Console.WriteLine("Load ClassLibrary1.dll success");
Type t= clib.GetType("ClassLibrary1.Class1");
object obj= Activator.CreateInstance(t);
t.GetMethod("Fn1").Invoke(obj, new object[] { });
Console.ReadKey();
//清理程序集加载上下文并开始卸载该上下文中加载的程序集
mlc.Unload();
Console.WriteLine("UnLoad ClassLibrary1.dll success");
}
测试程序集动态加载和卸载
cs
WeakReference testAlcWeakRef;
CallLib("E:\\projs\\analyze_dump\\example_net\\net_demo\\ClassLibrary1\\bin\\Debug\\net7.0\\ClassLibrary1.dll",out testAlcWeakRef);
//显示调用GC清理程序集加载上下文。
for (int i = 0; testAlcWeakRef.IsAlive && (i < 10); i++)
{
GC.Collect();
GC.WaitForPendingFinalizers();
}
Console.ReadKey();
成功加载程序集并实例化程序集中 Class1类并调用Fn1方法
在未卸载程序集前无法删除已加载的dll
卸载程序集后可以正常删除
动态加载和卸载程序集用途
动态更新程序,功能封装到独立的dll库。
应用插件化支持,动态扩展功能。