2009-10-10 55 views
18

我有一個程序集(作爲ReflectionOnly加載),我想查找此程序集中的所有名稱空間,以便將它們轉換爲「using」(「Imports」 VB)語句爲自動生成的源代碼文件模板。使用反射(DotNET)在程序集中查找所有名稱空間

理想情況下,我想自己限制在頂級命名空間而已,所以不是:

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

你只能得到:

using System; 

我注意到有一個命名空間屬性在System.Type類中,但是有沒有更好的方法來收集組件中的名稱空間,而不涉及遍歷所有類型和剔除重複的名稱空間字符串?

非常感激, 大衛

+1

萬一你不通知 - 有我有關如何在.NET 2.0中使用LINQ的回答下一個新的評論。 –

回答

29

不,這裏沒有捷徑,雖然LINQ使它相對容易。例如,在C#中生「組的命名空間」將是:

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

爲了得到頂級命名空間,而不是你應該寫一個方法:

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

我好奇來爲什麼你只需要頂級命名空間......這似乎是一個奇怪的約束。

+3

注意名稱空間可以爲空;也許是一些空合併/過濾。但除此之外......你知道,你擊敗了我(再次);-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

除了遍歷所有類,您將沒有別的選擇。

請注意,導入不能遞歸工作。 「使用系統」不會從子名稱空間(如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,謝謝你的樣品。該代碼是自動生成的,但隨後會暴露給用戶。所以我不想用數百個Imports和使用語句來污染源。但是由於典型的添加組件只有一些命名空間,所以我認爲選擇包含它們可能確實是一個好主意。 –

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()); 
} 
相關問題