You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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分支的程序集时,会:

  1. 正确加载所有嵌套依赖,完整获取测试方法信息
  2. 卸载后立即释放文件锁,允许重新构建或替换DLL文件

内容的提问来源于stack exchange,提问作者user19824680

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 14:40:19