.net 如何遍历当前加载的程序集?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/383686/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 10:51:40  来源:igfitidea点击:

How do you loop through currently loaded assemblies?

.netassemblies

提问by Jess Chadwick

I've got a "diagnostics" page in my ASP.NET application which does things like verify the database connection(s), display the current appSettings and ConnectionStrings, etc. A section of this page displays the Assembly versions of important types used throughout, but I could not figure out how to effectively show the versions of ALL of the loaded assemblies.

我的 ASP.NET 应用程序中有一个“诊断”页面,它执行诸如验证数据库连接、显示当前 appSettings 和 ConnectionStrings 等操作。此页面的一部分显示了整个过程中使用的重要类型的程序集版本,但我无法弄清楚如何有效地显示所有已加载程序集的版本。

What is the most effective way to figure out all currently referenced and/or loadedAssemblies in a .NET application?

找出.NET 应用程序中所有当前引用和/或加载的程序集的最有效方法是什么?

Note: I'm not interested in file-based methods, like iterating through *.dll in a particular directory. I am interested in what the application is actually usingright now.

注意:我对基于文件的方法不感兴趣,比如在特定目录中迭代 *.dll。我对应用程序现在实际使用的内容感兴趣。

采纳答案by Contango

This extension method gets all referenced assemblies, recursively, including nested assemblies.

此扩展方法以递归方式获取所有引用的程序集,包括嵌套程序集。

As it uses ReflectionOnlyLoad, it loads the assemblies in a separate AppDomain, which has the advantage of not interfering with the JIT process.

由于它使用ReflectionOnlyLoad,它将程序集加载到单独的 AppDomain 中,这具有不干扰 JIT 过程的优点。

You'll notice that there is also a MyGetMissingAssembliesRecursive. You can use this to detect any missing assemblies that are referenced, but not present in the current directory for some reason. This is incredibly useful when using MEF. The return list will give you both the missing assembly, and who owns it (its parent).

您会注意到还有一个MyGetMissingAssembliesRecursive. 您可以使用它来检测任何被引用但由于某种原因不在当前目录中的缺失程序集。这在使用MEF时非常有用。返回列表将为您提供丢失的程序集以及拥有它的人(其父级)。

/// <summary>
///     Intent: Get referenced assemblies, either recursively or flat. Not thread safe, if running in a multi
///     threaded environment must use locks.
/// </summary>
public static class GetReferencedAssemblies
{
    static void Demo()
    {
        var referencedAssemblies = Assembly.GetEntryAssembly().MyGetReferencedAssembliesRecursive();
        var missingAssemblies = Assembly.GetEntryAssembly().MyGetMissingAssembliesRecursive();
        // Can use this within a class.
        //var referencedAssemblies = this.MyGetReferencedAssembliesRecursive();
    }

    public class MissingAssembly
    {
        public MissingAssembly(string missingAssemblyName, string missingAssemblyNameParent)
        {
            MissingAssemblyName = missingAssemblyName;
            MissingAssemblyNameParent = missingAssemblyNameParent;
        }

        public string MissingAssemblyName { get; set; }
        public string MissingAssemblyNameParent { get; set; }
    }

    private static Dictionary<string, Assembly> _dependentAssemblyList;
    private static List<MissingAssembly> _missingAssemblyList;

    /// <summary>
    ///     Intent: Get assemblies referenced by entry assembly. Not recursive.
    /// </summary>
    public static List<string> MyGetReferencedAssembliesFlat(this Type type)
    {
        var results = type.Assembly.GetReferencedAssemblies();
        return results.Select(o => o.FullName).OrderBy(o => o).ToList();
    }

    /// <summary>
    ///     Intent: Get assemblies currently dependent on entry assembly. Recursive.
    /// </summary>
    public static Dictionary<string, Assembly> MyGetReferencedAssembliesRecursive(this Assembly assembly)
    {
        _dependentAssemblyList = new Dictionary<string, Assembly>();
        _missingAssemblyList = new List<MissingAssembly>();

        InternalGetDependentAssembliesRecursive(assembly);

        // Only include assemblies that we wrote ourselves (ignore ones from GAC).
        var keysToRemove = _dependentAssemblyList.Values.Where(
            o => o.GlobalAssemblyCache == true).ToList();

        foreach (var k in keysToRemove)
        {
            _dependentAssemblyList.Remove(k.FullName.MyToName());
        }

        return _dependentAssemblyList;
    }

    /// <summary>
    ///     Intent: Get missing assemblies.
    /// </summary>
    public static List<MissingAssembly> MyGetMissingAssembliesRecursive(this Assembly assembly)
    {
        _dependentAssemblyList = new Dictionary<string, Assembly>();
        _missingAssemblyList = new List<MissingAssembly>();
        InternalGetDependentAssembliesRecursive(assembly);

        return _missingAssemblyList;
    }

    /// <summary>
    ///     Intent: Internal recursive class to get all dependent assemblies, and all dependent assemblies of
    ///     dependent assemblies, etc.
    /// </summary>
    private static void InternalGetDependentAssembliesRecursive(Assembly assembly)
    {
        // Load assemblies with newest versions first. Omitting the ordering results in false positives on
        // _missingAssemblyList.
        var referencedAssemblies = assembly.GetReferencedAssemblies()
            .OrderByDescending(o => o.Version);

        foreach (var r in referencedAssemblies)
        {
            if (String.IsNullOrEmpty(assembly.FullName))
            {
                continue;
            }

            if (_dependentAssemblyList.ContainsKey(r.FullName.MyToName()) == false)
            {
                try
                {
                    var a = Assembly.ReflectionOnlyLoad(r.FullName);
                    _dependentAssemblyList[a.FullName.MyToName()] = a;
                    InternalGetDependentAssembliesRecursive(a);
                }
                catch (Exception ex)
                {
                    _missingAssemblyList.Add(new MissingAssembly(r.FullName.Split(',')[0], assembly.FullName.MyToName()));
                }
            }
        }
    }

    private static string MyToName(this string fullName)
    {
        return fullName.Split(',')[0];
    }
}

Update

更新

To make this code thread safe, put a lockaround it. It's not currently thread safe by default, as it references a shared static global variable to do its magic.

为了使此代码线程安全,请在其lock周围放置一个。默认情况下,它当前不是线程安全的,因为它引用了一个共享的静态全局变量来发挥它的魔力。

回答by Kent Boogaart

Getting loaded assemblies for the current AppDomain:

获取当前加载的程序集AppDomain

var loadedAssemblies = AppDomain.CurrentDomain.GetAssemblies();

Getting the assemblies referenced by another assembly:

获取另一个程序集引用的程序集:

var referencedAssemblies = someAssembly.GetReferencedAssemblies();

Note that if assembly A references assembly B and assembly A is loaded, that does not imply that assembly B is also loaded. Assembly B will only be loaded if and when it is needed. For that reason, GetReferencedAssemblies()returns AssemblyNameinstances rather than Assemblyinstances.

请注意,如果程序集 A 引用程序集 B 并且加载了程序集 A,这并不意味着也加载了程序集 B。只有在需要时才会加载程序集 B。因此,GetReferencedAssemblies()返回AssemblyName实例而不是Assembly实例。