Получение всех типов в пространстве имен с помощью отражения


269

Как вы получаете все классы в пространстве имен через отражение в C #?


Вы можете отредактировать свой вопрос ... подтекстный вопрос является более коммуникативным, чем «Пространство имен в C #»
Gishu

Вы можете посмотреть здесь . Есть 2 разных образца.
Фатих Гюрдал

Ответы:


317

Следующий код печатает имена классов в указанных, namespaceопределенных в текущей сборке.
Как отмечали другие ребята, пространство имен может быть разбросано по разным модулям, поэтому сначала нужно получить список сборок.

string nspace = "...";

var q = from t in Assembly.GetExecutingAssembly().GetTypes()
        where t.IsClass && t.Namespace == nspace
        select t;
q.ToList().ForEach(t => Console.WriteLine(t.Name));

83

Как говорит FlySwat, у вас может быть одно и то же пространство имен, охватывающее несколько сборок (например, System.Collections.Generic). Вам придется загрузить все эти сборки, если они еще не загружены. Итак, для полного ответа:

AppDomain.CurrentDomain.GetAssemblies()
                       .SelectMany(t => t.GetTypes())
                       .Where(t => t.IsClass && t.Namespace == @namespace)

Это должно работать, если вы не хотите классов других доменов. Чтобы получить список всех доменов, перейдите по этой ссылке.


1
работает отлично - небольшое напоминание: я пытался удалить " && t.Namespace == @namespace" - который, конечно, дал мне все сборки .net :-)
Netsi1964

@ Netsi1964 если вы удалите && t.Namespace == @namespaceвы получаете все классы из всех узлов , в том числе .net х. GetAssembliesпредоставит вам все сборки и GetAssemblies().SelectMany(t => t.GetTypes())все типы (классы, структуры и т. д.) из всех сборок.
Nawfal

Я обновил до DotNet Core 2.2 (с 2.1), и этот код перестал работать для моей конкретной сборки. Сборка, которую я хотел, нигде не упоминалась в коде, поэтому не была загружена! В 2.1 это было загружено, но у 2.2, кажется, есть ленивая загрузка?
Харви

@ Харви Есть ли у .NET Core домен приложения для начала?
nawfal

@nawfal Да. Этот код работал ранее в 2.1. Я обнаружил, что я принудительно загружаю сборку с помощью Assembly.Load(nameof(NameOfMyNamespace))работал нормально.
Харви

28
using System.Reflection;
using System.Collections.Generic;
//...

static List<string> GetClasses(string nameSpace)
{
    Assembly asm = Assembly.GetExecutingAssembly();

    List<string> namespacelist = new List<string>();
    List<string> classlist = new List<string>();

    foreach (Type type in asm.GetTypes())
    {
        if (type.Namespace == nameSpace)
            namespacelist.Add(type.Name);
    }

    foreach (string classname in namespacelist)
        classlist.Add(classname);

    return classlist;
}

NB: приведенный выше код иллюстрирует, что происходит. Если бы вы это реализовали, можно использовать упрощенную версию:

using System.Linq;
using System.Reflection;
using System.Collections.Generic;
//...

static IEnumerable<string> GetClasses(string nameSpace)
{
    Assembly asm = Assembly.GetExecutingAssembly();
    return asm.GetTypes()
        .Where(type => type.Namespace == nameSpace)
        .Select(type => type.Name);
}

9
Я не пытаюсь быть злым, но есть совершенно ненужный список и итерация по всем найденным элементам в этом коде; переменная «classlist» и foreach через «namespacelist» не предоставляют никакой функциональности, отличной от возврата «namespacelist»
TheXenocide

10
@ TheXenocide Цель примера кода не всегда состоит в том, чтобы показать «лучший» способ написания кода, но чтобы ясно показать, как что-то делается.
Райан Фарли

4
Я просто указывал на это ради образования; наша ответственность состоит в том, чтобы научить людей учиться на лучшем примере, который мы можем, вместо того, чтобы рисковать плохим примером, который негативно влияет на понимание. Я не говорю, что это в особенности вредно, но я не согласен с
мнением

4
Я отказываюсь от ответа, если он не помогает в вопросе, который был задан. Подсказка, которую вы видите при наведении курсора на кнопку «вверх / вниз», гласит: «Это было полезно». Для меня решение о том, чтобы проголосовать за вопрос вверх или вниз, заключается в том, было ли это полезным для ответа на заданный вопрос.
Райан Фарли

3
Единственное, что вам помогло, используя два списка и две итерации, - это замедлило меня, пытаясь понять, почему вы использовали два списка, а не просто добавили прямую к classlistпервой итерации по asm.GetTypes()результату.
ProfK

20

Для конкретной сборки NameSpace и ClassName:

var assemblyName = "Some.Assembly.Name"
var nameSpace = "Some.Namespace.Name";
var className = "ClassNameFilter";

var asm = Assembly.Load(assemblyName);
var classes = asm.GetTypes().Where(p =>
     p.Namespace == nameSpace &&
     p.Name.Contains(className) 
).ToList();

Примечание: проект должен ссылаться на сборку


12

Вот исправление ошибок LoaderException, которые вы, вероятно, найдете, если один из типов подклассов типа в другой сборке:

// Setup event handler to resolve assemblies
AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve += new ResolveEventHandler(CurrentDomain_ReflectionOnlyAssemblyResolve);

Assembly a = System.Reflection.Assembly.ReflectionOnlyLoadFrom(filename);
a.GetTypes();
// process types here

// method later in the class:
static Assembly CurrentDomain_ReflectionOnlyAssemblyResolve(object sender, ResolveEventArgs args)
{
    return System.Reflection.Assembly.ReflectionOnlyLoad(args.Name);
}

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

Надеюсь, это поможет!


Конечно, выглядит полезным, и менее полезным и менее запутанным, чем код Райана Фарли, даже не задумываясь об этом.
ProfK

Вы также немного запутали меня. Я до сих пор могу только догадываться, что Assembly aматериал представляет собой нормальную обработку, которая может вызвать это событие. Я не вижу смысла aв помощи с LoaderExceptionошибками. Я прав?
ProfK

9

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

Assembly.GetTypes()работает на локальной сборке, или вы можете сначала загрузить сборку, а затем вызвать GetTypes()ее.


2
+1 за правильный ответ. AppDomain.CurrentDomain.GetAssembliesможет быть полезным
Nawfal

... а затем перебрать их, отфильтровывая те, которые не соответствуют пространству имен.
TJ Crowder

В OP специально запрашивались «классы в пространстве имен», тогда как при этом вы получаете «типы в сборке», поэтому этот ответ неполон. Правильный ответ, вероятно, такой , который перечисляет только классы из всех сборок.
mindplay.dk

6

Точно так же, как ответ @aku, но с использованием методов расширения:

string @namespace = "...";

var types = Assembly.GetExecutingAssembly().GetTypes()
    .Where(t => t.IsClass && t.Namespace == @namespace)
    .ToList();

types.ForEach(t => Console.WriteLine(t.Name));

5

Получить все классы по части имени пространства имен в одной строке:

var allClasses = Assembly.GetExecutingAssembly().GetTypes().Where(a => a.IsClass && a.Namespace != null && a.Namespace.Contains(@"..your namespace...")).ToList();

3

Пространства имен на самом деле довольно пассивны в дизайне среды выполнения и служат главным образом как организационные инструменты. Полное имя типа в .NET состоит из пространства имен и класса / Enum / Etc. вместе взятые. Если вы хотите пройти только через определенную сборку, вы просто перебираете типы, возвращаемые сборкой. GetExportedTypes () проверяет значение типа. Пространство имен . Если вы пытаетесь просмотреть все сборки, загруженные в текущий AppDomain, это будет связано с использованием AppDomain.CurrentDomain. GetAssemblies ()


2
//a simple combined code snippet 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

namespace MustHaveAttributes
{
  class Program
  {
    static void Main ( string[] args )
    {
      Console.WriteLine ( " START " );

      // what is in the assembly
      Assembly a = Assembly.Load ( "MustHaveAttributes" );
      Type[] types = a.GetTypes ();
      foreach (Type t in types)
      {

        Console.WriteLine ( "Type is {0}", t );
      }
      Console.WriteLine (
         "{0} types found", types.Length );

      #region Linq
      //#region Action


      //string @namespace = "MustHaveAttributes";

      //var q = from t in Assembly.GetExecutingAssembly ().GetTypes ()
      //        where t.IsClass && t.Namespace == @namespace
      //        select t;
      //q.ToList ().ForEach ( t => Console.WriteLine ( t.Name ) );


      //#endregion Action  
      #endregion

      Console.ReadLine ();
      Console.WriteLine ( " HIT A KEY TO EXIT " );
      Console.WriteLine ( " END " );
    }
  } //eof Program


  class ClassOne
  {

  } //eof class 

  class ClassTwo
  {

  } //eof class


  [System.AttributeUsage ( System.AttributeTargets.Class |
    System.AttributeTargets.Struct, AllowMultiple = true )]
  public class AttributeClass : System.Attribute
  {

    public string MustHaveDescription { get; set; }
    public string MusHaveVersion { get; set; }


    public AttributeClass ( string mustHaveDescription, string mustHaveVersion )
    {
      MustHaveDescription = mustHaveDescription;
      MusHaveVersion = mustHaveVersion;
    }

  } //eof class 

} //eof namespace 

Какое AttributeClassимя MustHaveAttributesвсе о? Я не вижу ничего, связанного с проверкой, есть ли у класса атрибуты или нет. Это больше сбивает с толку, чем полезно.
ProfK

1

Довольно просто

Type[] types = Assembly.Load(new AssemblyName("mynamespace.folder")).GetTypes();
foreach (var item in types)
{
}

И просто не отвечая на вопрос. Все, что это делает, - это получение списка всех типов в одной сборке, независимо от конкретного пространства имен.
Ян
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.