Obtendo todos os tipos em um espaço para nome por reflexão

269

Como você obtém todas as classes em um espaço para nome através da reflexão em C #?

HB
fonte
você pode editar sua pergunta ... a questão do subtexto é mais comunicativa do que o 'Namespace in C #' #
392
Você pode procurar aqui . Existem 2 amostras diferentes.
Fatih GÜRDAL 15/11

Respostas:

317

O código a seguir imprime os nomes das classes especificadas namespacedefinidas na montagem atual.
Como outros caras apontaram, um espaço para nome pode ser espalhado entre diferentes módulos; portanto, é necessário obter uma lista dos assemblies primeiro.

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));
aku
fonte
83

Como o FlySwat diz, você pode ter o mesmo espaço para nome em vários assemblies (por exemplo System.Collections.Generic). Você precisará carregar todos esses conjuntos se eles ainda não estiverem carregados. Então, para uma resposta completa:

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

Isso deve funcionar, a menos que você queira classes de outros domínios. Para obter uma lista de todos os domínios, siga este link.

nawfal
fonte
1
funciona bem - um pequeno lembrete: Eu tentei remover " && t.Namespace == @namespace" - que ofcause me deu tudo .net montagens :-)
Netsi1964
@ Netsi1964, se você remover, && t.Namespace == @namespaceobtém todas as classes de todos os assemblies , incluindo os .net. GetAssembliesfornecerá todos os conjuntos e GetAssemblies().SelectMany(t => t.GetTypes())todos os tipos (classes, estruturas etc.) de todos os conjuntos.
Nawfal
Atualizei para o DotNet Core 2.2 (da 2.1) e esse código parou de funcionar para meu assembly específico. O assembly que eu queria não foi referenciado em nenhum lugar do código, portanto não foi carregado! Em 2.1 foi carregado, mas 2.2 parece ter carregamento lento?
Harvey
@ Harvey O .NET Core tem domínio de aplicativo para começar?
Nawfal 26/08/19
@nawfal Yeah. Este código funcionou anteriormente no 2.1. Descobri que forço o carregamento de uma montagem usando Assembly.Load(nameof(NameOfMyNamespace))funcionou bem.
Harvey
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;
}

Nota: O código acima ilustra o que está acontecendo. Se você implementá-lo, uma versão simplificada pode ser usada:

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);
}
Ryan Farley
fonte
9
Não estou tentando ser mesquinho, mas há uma lista e iteração totalmente desnecessárias em todos os itens encontrados neste código; a variável "classlist" e foreach através de "namespacelist" fornecer nenhuma funcionalidade diferente de retornar "namespacelist"
TheXenocide
10
@TheXenocide: o objetivo de uma amostra de código nem sempre tem como objetivo mostrar a "melhor" maneira de escrever código, mas transmitir claramente como algo é feito.
Ryan Farley
4
Eu estava apenas apontando isso por uma questão de educação; é nossa responsabilidade fazer com que as pessoas materiais aprendam com o melhor exemplo possível, em vez de arriscar um mau exemplo que influencia negativamente a compreensão. Não estou dizendo que este em particular é prejudicial, mas eu discordo com o sentimento
TheXenocide
4
Eu voto uma resposta para baixo, se não for útil para a pergunta que foi feita. A dica que você vê ao passar o mouse sobre o botão de votação para cima / para baixo diz "Isso foi útil". A decisão de votar para cima / para baixo em uma resposta, para mim, é se foi útil ou não para responder à pergunta.
22480 Ryan Farley
3
A única coisa que você usou duas listas e duas iterações ajudou foi me atrasar tentando descobrir por que você usou duas listas e não apenas adicionou diretamente à classlistprimeira iteração sobre o asm.GetTypes()resultado.
ProfK 26/10
20

Para um assembly específico, NameSpace e 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();

Nota: O projeto deve fazer referência à montagem

John Peters
fonte
12

Aqui está uma correção para os erros do LoaderException que você provavelmente descobrirá se um dos tipos sub-submete um tipo em outro assembly:

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

Isso deve ajudar no carregamento dos tipos definidos em outras montagens.

Espero que ajude!

tsimon
fonte
Certamente parece útil, e menos útil e menos confuso do que o código de Ryan Farley, mesmo sem pensar nisso.
ProfK 26/10/14
Você também me deixou confuso por um tempo. Ainda posso adivinhar que o Assembly amaterial representa o processamento normal que pode causar o disparo desse evento. Não vejo utilidade aem ajudar com LoaderExceptionerros. Estou certo?
ProfK 26/10/14
9

Você não poderá obter todos os tipos em um espaço para nome, porque um espaço para nome pode conectar vários assemblies, mas você pode obter todas as classes em um assembly e verificar se elas pertencem a esse espaço para nome.

Assembly.GetTypes()funciona na montagem local ou você pode carregar uma montagem primeiro e depois ligá GetTypes()-la.

FlySwat
fonte
2
+1 para a resposta correta. AppDomain.CurrentDomain.GetAssembliespode ser útil.
Nawfal
... e depois percorre-os, filtrando os que não correspondem ao espaço para nome.
TJ Crowder
O OP pediu especificamente "classes em um espaço para nome", enquanto isso faz com que você "digite um assembly" - portanto, essa resposta está incompleta. A resposta correta é provavelmente essa , que enumera apenas classes, de todos os assemblies.
mindplay.dk 14/04
6

Assim como a resposta @aku, mas usando métodos de extensão:

string @namespace = "...";

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

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

Obtenha todas as classes por parte do nome do espaço para nome em apenas uma linha:

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

Os espaços para nome são realmente bastante passivos no design do tempo de execução e servem principalmente como ferramentas organizacionais. O nome completo de um tipo no .NET consiste no espaço para nome e na classe / enum / etc. combinado. Se você deseja apenas passar por uma montagem específica, basta percorrer os tipos retornados pela montagem. GetExportedTypes () verificando o valor do tipo Namespace . Se você estivesse tentando passar por todos os assemblies carregados no AppDomain atual, isso envolveria o uso de AppDomain.CurrentDomain. GetAssemblies ()

TheXenocide
fonte
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 
Yordan Georgiev
fonte
Qual AttributeClasso nome do nome MustHaveAttributes? Não vejo nada relacionado a testar se uma classe tem atributos ou não. Isso é mais confuso do que útil.
ProfK 26/10/14
1

Bem simples

Type[] types = Assembly.Load(new AssemblyName("mynamespace.folder")).GetTypes();
foreach (var item in types)
{
}
Antonio Lopes
fonte
E simplesmente não respondendo à pergunta. Tudo o que está fazendo é obter uma lista de todos os tipos em um único assembly, independentemente de qualquer espaço para nome específico.
Ian