如何按依赖顺序获取当前应用的所有已加载程序集列表?
按依赖顺序获取已加载程序集的实现方案
我知道可以用AppDomain.GetAssemblies()获取当前应用的所有已加载程序集,但这个方法不保证返回顺序。我需要得到一个依赖程序集排在宿主程序集之前的列表,比如[B, A, A.Optional, A.Optional.Data, C](其中A.Optional.Data依赖A.Optional,A.Optional又依赖A;A、B、C相互独立,顺序无关)。是否能实现?
需求背景
我用MyAttribute标记了多个程序集中的多个类,最终项目需要收集这些类并注册,但注册顺序很关键——A.Optional里的类必须在A的类注册完成后才能正常工作。
当然可以实现,核心思路是基于程序集的依赖关系做拓扑排序,确保依赖项始终先于被依赖项出现。以下是具体实现步骤:
1. 构建程序集依赖映射
遍历所有已加载程序集,建立每个程序集与其直接依赖程序集的映射关系:
var assemblies = AppDomain.CurrentDomain.GetAssemblies(); var dependencyMap = new Dictionary<Assembly, List<Assembly>>(); foreach (var assembly in assemblies) { dependencyMap[assembly] = assembly.GetReferencedAssemblies() .Select(name => assemblies.FirstOrDefault(a => a.FullName == name.FullName)) .Where(refAssembly => refAssembly != null) .ToList(); }
2. 用Kahn算法做拓扑排序
通过入度表法实现拓扑排序,确保依赖顺序正确:
// 初始化入度表:记录每个程序集被多少其他程序集依赖 var inDegree = assemblies.ToDictionary(assembly => assembly, _ => 0); // 统计每个程序集的入度 foreach (var dependencies in dependencyMap.Values) { foreach (var dep in dependencies) { inDegree[dep]++; } } // 入度为0的程序集先入队(无依赖或依赖已处理) var queue = new Queue<Assembly>(inDegree.Where(kvp => kvp.Value == 0).Select(kvp => kvp.Key)); var sortedAssemblies = new List<Assembly>(); while (queue.Count > 0) { var currentAssembly = queue.Dequeue(); sortedAssemblies.Add(currentAssembly); // 遍历当前程序集的依赖项,减少其入度,入度为0则入队 foreach (var dependentAssembly in dependencyMap[currentAssembly]) { inDegree[dependentAssembly]--; if (inDegree[dependentAssembly] == 0) { queue.Enqueue(dependentAssembly); } } } // 检查是否存在循环依赖 if (sortedAssemblies.Count != assemblies.Length) { throw new InvalidOperationException("检测到程序集循环依赖,无法完成排序"); }
3. 结果验证
最终sortedAssemblies就是符合要求的有序列表:所有被依赖的程序集会排在依赖它的程序集之前,完全满足你的注册顺序需求。
注意事项
- 如果只需要处理业务程序集(排除系统程序集),可以在获取
assemblies时添加过滤条件:var assemblies = AppDomain.CurrentDomain.GetAssemblies() .Where(a => !a.FullName.StartsWith("System.") && !a.FullName.StartsWith("Microsoft.")) .ToList(); - 循环依赖会导致排序失败,需要提前排查项目中的循环依赖问题。
内容的提问来源于stack exchange,提问作者Luke Vo
相关产品推荐
相关产品推荐

