2016-08-03 64 views
0

我经常发现自己想要遍历当前环境中的所有类型,出于各种原因,例如查找从特定类继承的所有内容或查找具有特定属性的所有类型。找到引用特定程序集的所有其他程序集的最有效方法是什么?

我可以使用System.AppDomain.CurrentDomain.GetAssemblies()来获得所有程序集,然后在每个程序集上获得Assembly.GetTypes(),并迭代所有类型。但这是无效的低效率;在包含单个脚本的项目中的Unity编辑器中,此方法经历了8590种类型,其中大多数类型无法满足我正在搜索的标准。例如,mscorlib.dll或UnityEngine.dll中的任何内容都不会有我的自定义属性或从我的一个类继承,所以我应该跳过这些程序集。我试图找到引用任何给定程序集的所有程序集,但是我很难找出一个有效的算法来找到它们,因为我只能获取目标引用的程序集数组,不是引用目标的程序集数组。

另请注意,如果程序集A引用B和B引用C,那么当搜索引用CI的所有内容时,都需要同时获得A和B(如果B中的某些内容从我正在寻找的类继承而来, A没有直接引用C就继承了这个类)。

+0

您定位哪个.NET框架或.NET标准库? –

+0

对于第一种方法,如果过滤要迭代的程序集,则可能会加快速度。您可以只处理文件名以模式开头的程序集,或者将程序集列在配置文件中。如果可能,请在启动时执行此操作,并在“字典”或其他内容中建立缓存。 –

+0

对于第二种方法,您应该使用'assembly.GetReferencedAssemblies'使用递归函数创建引用程序集的树。为了加快速度,请跟踪您已经处理过一次的程序集。 –

回答

0

依赖性沃克将为你做这个魔术。

+0

Dependency Walker可以找到特定装配所依赖的所有东西。我需要找到所有依赖于特定装配的东西。另外,我需要在运行时以代码的形式执行它,以便可以遍历每个程序集中的类型。 – SilentSin

0

我从来没有使用Unity 2.0,所以我编写了这个.NET框架2.0,希望它的作品。

首先,你可以wanto创建组件树表示:

class DependencyTree 
{ 
    public string AssemblyName; 
    public IDictionary<string,DependencyTree> ReferencedAssemblies; 
} 

现在,让我们创建一个类来走,并生成树

class DependencyWalker 
{ 
    Dictionary<string, DependencyTree> _alreadyProcessed = new Dictionary<string, DependencyTree>(); 

    public DependencyTree GetDependencyTree(Assembly assembly) 
    { 
     // Avoid procesing twice same assembly. 
     if (_alreadyProcessed.ContainsKey(assembly.FullName)) 
      return _alreadyProcessed[assembly.FullName]; 

     var item = new DependencyTree(); 
     item.AssemblyName = assembly.FullName; 
     item.ReferencedAssemblies = new Dictionary<string, DependencyTree>(); 

     _alreadyProcessed.Add(item.AssemblyName, item); 

     foreach (AssemblyName assemblyName in assembly.GetReferencedAssemblies()) 
     { 
      item.ReferencedAssemblies.Add(assemblyName.FullName, GetDependencyTree(Assembly.Load(assemblyName))); 
     } 

     return item; 
    } 

    // To print the tree to the console: 
    public void PrintTree(DependencyTree tree) 
    { 
     PrintTree(tree, 0, new Dictionary<string, bool>()); // Using Dictionary because HashSet is not available on .NET 2.0 
    } 

    private void PrintTree(DependencyTree tree, int indentationLevel, IDictionary<string,bool> alreadyPrinted) 
    { 
     Console.WriteLine(new string(' ', indentationLevel) + tree.AssemblyName); 

     if (alreadyPrinted.ContainsKey(tree.AssemblyName)) 
      return; 

     alreadyPrinted[tree.AssemblyName] = true; 

     foreach (DependencyTree a in tree.ReferencedAssemblies.Values) 
      PrintTree(a, indentationLevel + 3, alreadyPrinted); 

    } 
} 

现在你可以easyly使用这个类:

class Program 
{ 
    static void Main(string[] args) 
    { 
     new System.Xml.XmlDocument().LoadXml("<xml/>"); // Do whatever to ensure System.Xml assembly is referenced. 

     var startingAssembly = typeof(Program).Assembly; 
     var walker = new DependencyWalker(); 
     var tree = walker.GetDependencyTree(startingAssembly); 
     walker.PrintTree(tree); 
    } 
} 

其中输出;

 
ConsoleApplication1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null 
    mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 
    System.Xml, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 
     mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 
     System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 
     mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 
     System.Configuration, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a 
      mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 
      System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 
      System.Xml, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 
      System.Security, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a 
       mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 
       System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 
       System.Xml, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 
     System.Xml, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 
     System.Configuration, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a 
     System.Data.SqlXml, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 
     System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 
     mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 
     System.Xml, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 

请注意,生成器输出一个有循环的树,所以遍历它的递归函数将是一个无限循环。在PrintTree中,我通过使用alreadyPrinted列表来避免无限循环。 (我只打印一次子引用列表以避免循环。)YMMV,请根据您的需要进行更改。

相关问题