如何获取所有被引用的程序集列表(不管是否已加载)

4

我正在尝试获取MEF中加载到主应用程序中的程序集的引用列表。

在运行插件之前,我希望确保所有引用的程序集都存在于文件夹中。

我尝试使用

List<AssemblyName> a = Assembly.GetEntryAssembly().GetReferencedAssemblies().ToList();

但是当我这样做时,它只显示了在那个阶段使用/加载的程序集。我想要一个完整的列表(在运行时)引用的程序集(类似于VS中的References文件夹),无论它们是否在此时或根本没有被使用。

3个回答

1
你可以从文件元数据中提取这些信息。最快的方法可能是使用其中一个库来实现。
例如,你可以使用Mono.Cecil
就像这样:
var md = ModuleDefinition.ReadModule(assemblyPath);
foreach (var reference in md.AssemblyReferences)
{

}

1
在加载插件之前,您可以仅加载反射以仅加载文件的元数据。例如:
    var assm = Assembly.ReflectionOnlyLoadFrom(@"Same.dll");
    var reff = assm.GetReferencedAssemblies();

请记住,相关的库可以有它们自己的引用。


欢迎来到Stack Overflow!虽然这段代码可能回答了问题,但最好还是加入一些上下文,解释它的工作原理,并描述何时使用它。仅有代码的答案从长远来看并不实用。 - ryanyuyu
@Juan 我尝试了你提供的两种方法,它们都返回相同的列表。这是我期望得到的结果和实际得到的结果的图片。绿点表示包含在结果列表中的引用,红点表示不包含在其中的引用。http://i58.tinypic.com/169glly.png - Attie
因为这些库没有在你的库中使用,元信息也不包含有关它们的信息。 - MIVer
@MIVer,那我很困惑,抱歉。因为当我删除其中任何一个引用时,由于缺少引用,我无法编译我的项目? - Attie
嗯... 可能这些库需要我上面列出的依赖库之一。我认为你不仅需要进行依赖分析,还需要进行递归依赖分析。 - MIVer

0
我也曾经为此苦恼,最终找到了Assembly.GetReferencedAssemblies()。这个方法可以返回一个程序集中所有被引用的程序集。但是,如果你想获取整个应用程序中所有被引用的程序集,你需要进行传递闭包操作,以获取被引用程序集所引用的程序集,以此类推。
以下是我使用的函数:
    private static List<Assembly> GetAllReferencedAssemblies(Assembly asm)
    {
        var nameQueue = new Queue<AssemblyName>(asm.GetReferencedAssemblies());
        var alreadyProcessed = new HashSet<string>() { asm.FullName };
        var result = new List<Assembly>();
        result.Add(asm);
        while (nameQueue.Any())
        {
            var name = nameQueue.Dequeue();
            var fullName = name.FullName;
            if (alreadyProcessed.Contains(fullName) || fullName.StartsWith("Microsoft.") || fullName.StartsWith("System."))
                continue;
            alreadyProcessed.Add(fullName);
            try
            {
                var newAssembly = Assembly.Load(name);
                result.Add(newAssembly);
                foreach (var innerAsmName in newAssembly.GetReferencedAssemblies())
                    nameQueue.Enqueue(innerAsmName);
                Debug.WriteLine(name);
            }
            catch (Exception e)
            {
                Debug.WriteLine(e);
            }
        }

        return result;
    }

一些实用的要点:你会发现我添加了一行来排除Microsoft和System程序集--如果你深入研究这个问题,你会得到很多奇怪的程序集。然而,你可以根据自己的需要进行调整。此外,我在Assembly.Load中包含了一个try/catch块,因为我的经验是有时候你会遇到一些无法加载的dll,或者它们已经不再使用了。同样,你可以随意处理这个问题。
显然,对于使用的顶级程序集,主程序或其他程序,你可以轻松地调用它,例如:
var asmList = GetAllReferencedAssemblies(typeof(Main).Assembly);

main 是您顶层程序集中的一种类型。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接