2016-08-03 8 views
0

特定のクラスから継承するすべてのものを見つけたり、特定の属性を持つすべての型を見つけるなど、さまざまな理由で、現在の環境ですべての型を反復処理したいことがよくあります。特定のアセンブリを参照する他のすべてのアセンブリを見つける最も効率的な方法は何ですか?

System.AppDomain.CurrentDomain.GetAssemblies()を使用してすべてのアセンブリを取得し、次にAssembly.GetTypes()をすべて使用してすべてのタイプを反復処理することができます。しかし、これは不必要に非効率的です。単一のスクリプトを含むプロジェクトのUnityエディタでは、このメソッドは8590型を処理しますが、その大部分は私がとにかく検索している基準を満たすことができません。たとえば、mscorlib.dllやUnityEngine.dllの中には、自分のカスタム属性を持ったり、クラスから継承したりするものがないので、これらのアセンブリをスキップするだけです。

これで、特定のアセンブリを参照するアセンブリをすべて見つけようとしていますが、ターゲットが参照するアセンブリの配列しか取得できないため、効率的なアルゴリズムを見つけるのに問題があります。ターゲットを参照するアセンブリの配列ではありません。

また、アセンブリAがBとBを参照する場合は、CIを参照するすべてのものを検索するとAとBの両方を取得する必要があることに注意してください(Bの何かが私が探しているクラスから継承し、 AはCを直接参照しないでそのクラスから継承します)。

+0

対象とする.NETフレームワークまたはNET標準ライブラリはどれですか? –

+0

最初のアプローチでは、どのアセンブリを繰り返し処理するかをフィルタリングすると処理速度が向上する可能性があります。パターンで始まるファイル名でアセンブリのみを処理することも、構成ファイルにアセンブリをリストすることもできます。可能であれば、起動時にそれを行い、辞書などにキャッシュを構築します。 –

+0

2つ目のアプローチでは、再帰関数を使用して、参照されたアセンブリのツリーを 'assembly.GetReferencedAssemblies'で作成する必要があります。作業をスピードアップするには、すでに処理したアセンブリを追跡してください。 –

答えて

0

依存性ウォーカーはあなたのためにその魔法を行います。

+0

依存関係ウォーカーは、特定のアセンブリが依存するすべてのものを検出します。私は、特定のアセンブリに依存するすべてを見つける必要があります。また、実行時にコード内で行う必要があるため、各アセンブリの型をループすることができます。 – SilentSin

0

Unity 2.0を一度も使用していないので、.NET Framework 2.0用にこれをコーディングしました。うまくいきたいと思います。あなたがアセンブリのツリー表現を作成することwantoも

まず:

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

今すぐあなたがeasylyこのクラスを使用することができ、ツリーに

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

    } 
} 

を歩くと、生成するクラスを作成することができます:

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リストを使用して無限ループを回避します。 (私はループを避けるために子参照リストを1回だけ印刷します。)YMMVので、必要に応じて変更してください。

関連する問題