I\'ve got an assembly (loaded as ReflectionOnly) and I want to find all the namespaces in this assembly so I can convert them into \"using\" (\"Imports\" in VB) statements f
You will have no other choice than iterating over all classes.
Note that imports don't work recursively. "using System" won't import any classes from subnamespaces like System.Collections or System.Collections.Generic, instead you must include them all.
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());
}
Namespaces are really just a naming convention in type names, so they only "exist" as a pattern that is repeated across many qualified type names. So you have to loop through all the types. However, the code for this can probably be written as a single Linq expression.
A bit of 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);
}
Here's a sort of linq'ish way, it still in essence is itterating over every element but the code is much cleaner.
var nameSpaces = from type in Assembly.GetExecutingAssembly().GetTypes()
select type.Namespace;
nameSpaces = nameSpaces.Distinct();
Also if your auto generating code, you might be better off to fully qualify everything, then you won't have to worry about naming conflicts in the generated code.
No, there's no shortcut for this, although LINQ makes it relatively easy. For example, in C# the raw "set of namespaces" would be:
var namespaces = assembly.GetTypes()
.Select(t => t.Namespace)
.Distinct();
To get the top-level namespace instead you should probably write a method:
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);
}
I'm intrigued as to why you only need top level namespaces though... it seems an odd constraint.