Поиск всех пространств имен в сборке с использованием Reflection (DotNET) - PullRequest
20 голосов
/ 11 октября 2009

У меня есть сборка (загруженная как ReflectionOnly), и я хочу найти все пространства имен в этой сборке, чтобы я мог преобразовать их в операторы "using" ("Imports" в VB) для автоматически сгенерированного файла исходного кода шаблон.

В идеале я хотел бы ограничиться только пространствами имен верхнего уровня, поэтому вместо:

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

вы получите только:

using System;

Я заметил, что в классе System.Type есть свойство Namespace, но есть ли лучший способ сбора пространств имен внутри сборки, который не включает в себя перебор всех типов и отбраковку дублирующихся строк пространства имен?

Очень благодарен, David

Ответы [ 6 ]

34 голосов
/ 11 октября 2009

Нет, для этого нет ярлыка, хотя 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);
}

Я заинтригован тем, почему вам нужны только пространства имен верхнего уровня, хотя ... это кажется странным ограничением.

4 голосов
/ 11 октября 2009

Пространства имен - это на самом деле просто соглашение об именах в именах типов, поэтому они «существуют» только как шаблон, повторяющийся во многих квалифицированных именах типов. Таким образом, вы должны пройти через все типы. Однако код для этого, вероятно, может быть записан в виде одного выражения Linq.

2 голосов
/ 11 октября 2009

Немного 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);
}
2 голосов
/ 11 октября 2009

Вот что-то вроде linq'ish, он по-прежнему по сути итерирует по каждому элементу, но код намного чище.

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

Кроме того, если вы автоматически генерируете код, возможно, вам лучше полностью его квалифицировать, тогда вам не придется беспокоиться о конфликтах имен в сгенерированном коде.

1 голос
/ 11 октября 2009
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());
}
1 голос
/ 11 октября 2009

У вас не будет другого выбора, кроме как перебирать все классы.

Обратите внимание, что импорт не работает рекурсивно. «Использование системы» не будет импортировать какие-либо классы из подпространств, таких как System.Collections или System.Collections.Generic, вместо этого вы должны включить их все.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...