如何在运行时可靠检测动态加载的DLL是否已卸载?
动态加载DLL的卸载检测问题
我在.NET 7 WPF应用中有这样的场景:数据网格列使用用户自定义的C#脚本,用户修改脚本后会编译生成新的DLL,这时候需要卸载旧版本的DLL。
按照官方文档的思路做了测试,用自定义AssemblyLoadContext加载DLL,但遇到了异常情况:
- 点击Button1调用
RunTest方法时,从创建上下文、加载DLL、执行逻辑到卸载的流程是完整的,之后弱引用的IsAlive会变为false,符合预期 - 但把逻辑拆分成
RunTest2和Button2_Click两个阶段后,先创建上下文再执行卸载,弱引用的IsAlive始终为true,不过VS的「Modules」窗口里已经看不到这个DLL了
我想搞清楚:是我对弱引用的使用有误,还是对VS模块窗口的理解有偏差?另外,有没有一种可靠的方法可以检测DLL是否已经被卸载?
测试代码如下:
private void Button1_Click(object sender, RoutedEventArgs e) { var spo = model.GetDataObject(0); RunTest(spo, @"dll_2098706330365.dll"); // 正常工作 RunTest2(spo, @"dll_2098706330365.dll"); // 异常 } private void Button2_Click(object sender, RoutedEventArgs e) { WeakReference weakRef; TestUnload22(alc, out weakRef); TestUnload23(weakRef); } MyAssemblyLoader alc; public void RunTest(DataObject spo, string path) { WeakReference weakRef; TestUnload(path, spo, out weakRef); for (int i = 0; weakRef.IsAlive && (i < 10); i++) { GC.Collect(); GC.WaitForPendingFinalizers(); Debug.WriteLine(" >>> UnloadTest: attemtp: {0} Weak ref {1}", i, weakRef.IsAlive); } Debug.WriteLine(">>> RunTest: ended {0}", weakRef.IsAlive); } [MethodImpl(MethodImplOptions.NoInlining)] private void TestUnload(string path, DataObject spo, out WeakReference weakRef) { var alc = new MyAssemblyLoader (path); Assembly a = alc.LoadFromAssemblyPath(path); weakRef = new WeakReference(alc, trackResurrection: true); var scriptInstance = InstantiateScript(a); var result = scriptInstance.Evaluate(spo, null)?.ToString(); Debug.WriteLine(" >>> Evaluate: " + result); alc.Unload(); } public void RunTest2(ISPDataObject spo, string path) { TestUnload2(path, spo); } [MethodImpl(MethodImplOptions.NoInlining)] private void TestUnload2(string path, ISPDataObject spo) { alc = new MyAssemblyLoader (path); Assembly a = alc.LoadFromAssemblyPath(path); } [MethodImpl(MethodImplOptions.NoInlining)] private void TestUnload22(MyAssemblyLoader alc, out WeakReference weakRef) { weakRef = new WeakReference(alc, trackResurrection: true); alc.Unload(); } private void TestUnload23(WeakReference weakRef) { for (int i = 0; weakRef.IsAlive && (i < 10); i++) { GC.Collect(); GC.WaitForPendingFinalizers(); Debug.WriteLine(" >>> UnloadTest2: attemtp: {0} Weak ref {1}", i, weakRef.IsAlive); } Debug.WriteLine(">>> RunTest2: ended {0}", weakRef.IsAlive); }
内容的提问来源于stack exchange,提问作者Boppity Bop
相关产品推荐
相关产品推荐

