使用Reflection(DotNET)查找程序集中的所有命名空间

我有一个程序集(作为ReflectionOnly加载),我想找到这个程序集中的所有命名空间,所以我可以将它们转换为自动生成的源代码文件模板的“using”(VB中的“Imports”)语句。

理想情况下,我只想将自己限制在顶级命名空间,而不是:

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

你只会得到:

 using System; 

我注意到System.Type类上有一个Namespace属性,但有没有更好的方法来收集程序集内的命名空间,而不涉及迭代所有类型并剔除重复的命名空间字符串?

大卫,很有责任

不,这没有捷径,虽然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); } 

我很感兴趣为什么你只需要顶级命名空间……这似乎是一个奇怪的约束。

命名空间实际上只是类型名称中的命名约定,因此它们仅作为在许多限定类型名称中重复的模式“存在”。 所以你必须遍历所有类型。 但是,此代码可能会写为单个Linq表达式。

这是一种linq’ish方式,它实质上仍然是对每个元素的迭代,但代码更清晰。

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

此外,如果您的自动生成代码,您可能最好完全限定所有内容,那么您将不必担心生成的代码中的命名冲突。

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

除了迭代所有类之外别无选择。

请注意,导入不能递归地工作。 “using System”不会从System.Collections或System.Collections.Generic等子名称空间导入任何类,而是必须包含所有类。

 public static void Main() { var assembly = ...; Console.Write(CreateUsings(FilterToTopLevel(GetNamespaces(assembly)))); } private static string CreateUsings(IEnumerable namespaces) { return namespaces.Aggregate(String.Empty, (u, n) => u + "using " + n + ";" + Environment.NewLine); } private static IEnumerable FilterToTopLevel(IEnumerable namespaces) { return namespaces.Select(n => n.Split('.').First()).Distinct(); } private static IEnumerable GetNamespaces(Assembly assembly) { return (assembly.GetTypes().Select(t => t.Namespace) .Where(n => !String.IsNullOrEmpty(n)) .Distinct()); }