从 .Net Core 3.0开始支持程序集的加载和卸载,在 .Net FrameWork中使用独立的应用程序域来实现同样的功能,.Net Core 不支持创建多个应用程序域,所以无法使用多个应用程序域来实现程序集动态加载和卸载。
AssemblyLoadContext
程序集加载上下文,它代表一个程序集加载域,在这个域中可以加载、解析、卸载程序集
创建一个 .Net 库项目
public class Class1{public void Fn1(){Console.WriteLine("Fn1");}public void Fn2(){Console.WriteLine("Fn2");}}
创建一个控制台项目
实现一个自定义程序集加载上下文类, isCollectible 表示是否支持程序集卸载,默认是 false,所以需要从 AssemblyLoadContext 继承并实现一个AssemblyLoadContext。
internal class MyAssemblyContext:AssemblyLoadContext{public MyAssemblyContext() : base(isCollectible: true){ }}
测试加载和卸载方法
//告诉编译器不要内联该方法,防止栈上存在引用导致无法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");}
测试程序集动态加载和卸载
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库。
应用插件化支持,动态扩展功能。