2009-10-10 8 views
18

アセンブリ(ReflectionOnlyとしてロード)があり、 VB)ステートメントを自動生成されたソースコードファイルテンプレートに適用します。Reflection(DotNET)を使用してアセンブリ内のすべての名前空間を見つける

理想的には私が唯一のトップレベルの名前空間に自分自身を制限するのが好きなので、代わりの思い:

using System; 
using System.Collections; 
using System.Collections.Generic; 

あなただけ取得したい:

using System; 

を私はNamespaceプロパティがある気づきましたSystem.Typeクラスにはありますが、すべての型の繰り返し処理や重複する名前空間文字列の削除を伴わないネームスペースをアセンブリ内で収集する良い方法はありますか?多くの義務が

、 デビッド

+1

念のため、あなたは通知されません - .NET 2.0でのLINQを使用する方法についての私の答えの下に新しいコメントがあります。 –

答えて

29

いいえ、LINQは比較的簡単ですが、これには簡単な方法はありません。たとえば、C#で生の「名前空間のセットは、」次のようになります。

var topLevel = assembly.GetTypes() 
         .Select(t => GetTopLevelNamespace(t)) 
         .Distinct(); 

... 

static string GetTopLevelNamespace(Type t) 
{ 
    string ns = t.Namespace ?? ""; 
    int firstDot = ns.IndexOf('.'); 
    return firstDot == -1 ? ns : ns.Substring(0, firstDot); 
} 

私がするように興味をそそらだ:

var namespaces = assembly.GetTypes() 
         .Select(t => t.Namespace) 
         .Distinct(); 

ではなく、あなたはおそらくメソッドを記述する必要があり、トップレベルの名前空間を取得するにはなぜトップレベルの名前空間だけが必要なのですか...それは奇妙な制約のようです。

+3

名前空間がnullでもかまわないことに注意してください。おそらくいくつかのヌル - 合体/フィルタリング。しかし、そうでなければ...あなたは私を(もう一度)打ち負かしました;-p –

+1

無礼で良いお呼び。 「トップレベルのみ」の制約が違っていると理解しています。ご心配ください。 –

+0

いいえ、私は単純に間違ってコードしました(削除された投稿のコメントを参照) - 私のバージョンは、タイプがトップレベルの名前空間でのみ機能していました。 –

4

名前空間は本当にタイプ名にちょうど命名規則なので、唯一の多くの修飾タイプ名にわたって繰り返されるパターンとして「存在します」。だから、すべてのタイプをループする必要があります。しかし、このコードはおそらく単一のLinq式として記述することができます。

+0

ありがとうEarwicker。 Linqは手が届かず(まだDotNET 2.0で作業中ですが)、すべてのタイプに対して反復処理を行うのは、linq以外では約20行のコードしか必要としません。 –

+1

BclExtras - http://code.msdn.microsoft.com/BclExtrasを必ずチェックしてください - 拡張メソッド属性とほとんどの 'IEnumerable'拡張の条件付きコンパイル済みブロックの定義を提供します。したがって、これらの回答にLinqコードを使用することはできますが、まだ.NET 2.0をターゲットにしています。 –

1

あなたは、すべてのクラスを反復する以外の方法はありません。

インポートが再帰的に機能しないことに注意してください。 "using System"は、System.CollectionsやSystem.Collections.Genericのようなサブネームスペースからクラスをインポートするのではなく、それらをすべて含める必要があります。

+0

ありがとうCodyManix、私は再帰的な名前空間の包含を可能にするオプションを提供すると思います。とにかく多くの名前空間を持たないので、ほとんどの追加のアセンブリで大きな問題はありません。 –

2

ここにはlinq'ishのやり方があります。それは本質的にすべての要素を繰り返し処理していますが、コードははるかにクリーンです。また

var nameSpaces = from type in Assembly.GetExecutingAssembly().GetTypes() 
       select type.Namespace; 
nameSpaces = nameSpaces.Distinct(); 

あなたの自動生成コードであれば、あなたは、あなたが生成されたコードでの名前の競合を心配する必要はありません、完全にすべてのものを修飾する方が良いかもしれません。

+0

@Josh、サンプルをありがとう。コードは自動的に生成されますが、ユーザーに公開されます。だから私は何百もの輸入品と出典を汚染することを望まない。しかし、典型的なアセンブリのほうがいくつかの名前空間しか持たないので、おそらくそれらをすべて含めるという選択肢を持つことは良い考えです。 –

2

ビットのLINQ?

var qry = (from type in assembly.GetTypes() 
      where !string.IsNullOrEmpty(type.Namespace) 
      let dotIndex = type.Namespace.IndexOf('.') 
      let topLevel = dotIndex < 0 ? type.Namespace 
       : type.Namespace.Substring(0, dotIndex) 
      orderby topLevel 
      select topLevel).Distinct(); 
foreach (var ns in qry) { 
    Console.WriteLine(ns); 
} 
1
public static void Main() { 

    var assembly = ...; 

    Console.Write(CreateUsings(FilterToTopLevel(GetNamespaces(assembly)))); 
} 

private static string CreateUsings(IEnumerable<string> namespaces) { 
    return namespaces.Aggregate(String.Empty, 
           (u, n) => u + "using " + n + ";" + Environment.NewLine); 
} 

private static IEnumerable<string> FilterToTopLevel(IEnumerable<string> namespaces) { 
    return namespaces.Select(n => n.Split('.').First()).Distinct(); 
} 

private static IEnumerable<string> GetNamespaces(Assembly assembly) { 
    return (assembly.GetTypes().Select(t => t.Namespace) 
      .Where(n => !String.IsNullOrEmpty(n)) 
      .Distinct()); 
}