当前位置:  开发笔记 > 编程语言 > 正文

如何循环当前加载的程序集?

如何解决《如何循环当前加载的程序集?》经验,为你挑选了2个好方法。

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

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

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



1> Kent Boogaar..:

获取当前加载的程序集AppDomain:

var loadedAssemblies = AppDomain.CurrentDomain.GetAssemblies();

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

var referencedAssemblies = someAssembly.GetReferencedAssemblies();

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


OP询问_currently loaded_ assemblies未引用的程序集.这回答了这个问题.正是我在寻找什么.
我需要这样的东西 - 给定.net解决方案我想找出所有项目中所有引用的程序集.想法?

2> Contango..:

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

在使用时ReflectionOnlyLoad,它将程序集加载到单独的AppDomain中,这样做的好处是不会干扰JIT进程.

你会发现还有一个MyGetMissingAssembliesRecursive.您可以使用它来检测引用的任何缺少的程序集,但由于某种原因不在当前目录中.这在使用MEF时非常有用.返回列表将为您提供缺少的程序集以及谁拥有它(其父项).

/// 
///     Intent: Get referenced assemblies, either recursively or flat. Not thread safe, if running in a multi
///     threaded environment must use locks.
/// 
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 _dependentAssemblyList;
    private static List _missingAssemblyList;

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

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

        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;
    }

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

        return _missingAssemblyList;
    }

    /// 
    ///     Intent: Internal recursive class to get all dependent assemblies, and all dependent assemblies of
    ///     dependent assemblies, etc.
    /// 
    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];
    }
}
更新

为了使这个代码线程安全,请放置lock它.它默认情况下当前不是线程安全的,因为它引用了一个共享的静态全局变量来实现其魔力.


添加一个`lock`不会增加"线程安全"的方式.当然,这使得该代码块一次只执行一个; 但是其他线程可以随时加载程序集,这可能会导致某些`foreach`循环出现问题.
使这个线程安全的天真方法是在整个事物周围放置一个"锁定".我使用的另一种方法消除了对全局静态"_dependentAssemblyList"的依赖,因此它变得线程安全,而不需要`lock`,如果多个线程试图同时确定缺少哪些程序集,这会有一些轻微的速度优势(这是一点角落的情况).
推荐阅读
女女的家_747
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有