使用AssemblyLoadContext加载程序集时嵌套集未加载且无法卸载锁定问题
程序集加载不全与卸载后文件锁定问题解决方案
针对你遇到的两个问题,下面给出具体的修复方案和代码修改:
问题1:嵌套程序集未加载导致无法获取测试方法
核心原因
当前的TestAssemblyLoadContext.Load方法仅通过AssemblyDependencyResolver解析依赖,部分嵌套依赖(比如依赖的依赖)可能无法被正确解析;此外,若解析失败直接返回null,CLR会回退到默认加载上下文加载依赖,导致依赖无法被后续卸载,同时可能引发类型加载失败。
修复方案
扩展Load方法的解析逻辑,确保所有相关依赖都通过当前自定义ALC加载,仅让系统程序集回退到默认上下文:
public class TestAssemblyLoadContext : AssemblyLoadContext { private readonly AssemblyDependencyResolver _resolver; private readonly string _assemblyDirectory; public TestAssemblyLoadContext(string pluginPath) : base(isCollectible: true) { _resolver = new AssemblyDependencyResolver(pluginPath); _assemblyDirectory = Path.GetDirectoryName(pluginPath); } protected override Assembly Load(AssemblyName name) { // 优先用依赖解析器查找 string assemblyPath = _resolver.ResolveAssemblyToPath(name); if (assemblyPath != null) { Console.WriteLine($"Loading assembly {assemblyPath} into TestAssemblyLoadContext"); return LoadFromAssemblyPath(assemblyPath); } // 尝试从主程序集目录查找嵌套依赖 var localPath = Path.Combine(_assemblyDirectory, $"{name.Name}.dll"); if (File.Exists(localPath)) { Console.WriteLine($"Loading local assembly {localPath} into TestAssemblyLoadContext"); return LoadFromAssemblyPath(localPath); } // 系统程序集回退到默认上下文加载 return Default.LoadFromAssemblyName(name); } }
问题2:Unload后程序集仍被锁定无法重新构建
核心原因
返回的MethodInfo对象持有对原程序集、类型的强引用,导致自定义ALC无法被GC回收,进而持续锁定文件。
修复方案
将测试方法的关键信息复制到独立的DTO类中,切断对原程序集的引用;同时强制触发GC确保ALC被回收:
1. 定义测试方法信息DTO
public class TestMethodInfo { public string TypeFullName { get; set; } public string MethodName { get; set; } public bool HasTestAttribute { get; set; } public bool HasTestCaseAttribute { get; set; } public string Namespace => TypeFullName?.Substring(0, TypeFullName.LastIndexOf('.')); }
2. 修改GetMethods方法
private static List<TestMethodInfo> GetMethods(string assemblyPath) { TestAssemblyLoadContext alc = null; try { alc = new TestAssemblyLoadContext(assemblyPath); var assembly = alc.LoadFromAssemblyPath(assemblyPath); var testMethods = new List<TestMethodInfo>(); foreach (var type in assembly.GetTypes()) { foreach (var method in type.GetMethods()) { var hasTestAttr = method.GetCustomAttributes(typeof(TestAttribute), false).Any(); var hasTestCaseAttr = method.GetCustomAttributes(typeof(TestCaseAttribute), false).Any(); if (hasTestAttr || hasTestCaseAttr) { testMethods.Add(new TestMethodInfo { TypeFullName = type.FullName, MethodName = method.Name, HasTestAttribute = hasTestAttr, HasTestCaseAttribute = hasTestCaseAttr }); } } } return testMethods.OrderBy(tm => tm.Namespace).ToList(); } finally { if (alc != null) { alc.Unload(); // 强制触发GC回收,确保ALC及关联资源释放 GC.Collect(); GC.WaitForPendingFinalizers(); GC.Collect(); } } }
最终效果
修改后,两次调用GetMethods分别加载不同Git分支的程序集时,会:
- 正确加载所有嵌套依赖,完整获取测试方法信息
- 卸载后立即释放文件锁,允许重新构建或替换DLL文件
内容的提问来源于stack exchange,提问作者user19824680
相关产品推荐
相关产品推荐

