Ottenere tutti i tipi in uno spazio dei nomi tramite la riflessione


269

Come si ottengono tutte le classi in uno spazio dei nomi tramite la riflessione in C #?


puoi modificare la tua domanda ... la domanda del sottotesto è più comunicativa dello "Spazio dei nomi in C #"
Gishu,

Puoi guardare qui . Ci sono 2 campioni diversi.
Fatih GÜRDAL,

Risposte:


317

Il codice seguente stampa i nomi delle classi specificate namespacenell'assembly corrente.
Come altri ragazzi hanno sottolineato, uno spazio dei nomi può essere distribuito tra diversi moduli, quindi è necessario prima ottenere un elenco di assiemi.

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

Come dice FlySwat, è possibile avere lo stesso spazio dei nomi che si estende in più assiemi (ad esempio System.Collections.Generic). Dovrai caricare tutti quegli assembly se non sono già stati caricati. Quindi per una risposta completa:

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

Questo dovrebbe funzionare a meno che tu non voglia classi di altri domini. Per ottenere un elenco di tutti i domini, segui questo link.


1
funziona bene - un piccolo promemoria: ho provato a rimuovere " && t.Namespace == @namespace" - che spesso mi ha dato tutti gli assembly .net :-)
Netsi1964,

@ Netsi1964 se rimuovi && t.Namespace == @namespaceottieni tutte le classi di tutti gli assembly , inclusi quelli di .net. GetAssembliesti darà tutti gli assembly e GetAssemblies().SelectMany(t => t.GetTypes())ti darà tutti i tipi (classi, strutture ecc.) di tutti gli assembly.
nawfal,

Ho eseguito l'aggiornamento a DotNet Core 2.2 (da 2.1) e questo codice ha smesso di funzionare per il mio specifico assembly. L'assembly che volevo non faceva riferimento in nessuna parte del codice, quindi non è stato caricato! In 2.1 è stato caricato, ma 2.2 sembra avere un caricamento lento?
Harvey,

@Harvey .NET Core ha l'appdomain per cominciare?
nawfal,

@nawfal Sì. Questo codice ha funzionato in precedenza in 2.1. Ho scoperto che forzare il caricamento di un assieme usando Assembly.Load(nameof(NameOfMyNamespace))funzionava perfettamente.
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;
}

NB: il codice sopra mostra cosa sta succedendo. Se lo si implementasse, è possibile utilizzare una versione semplificata:

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
Non sto cercando di essere cattivo, ma c'è un elenco e un'iterazione del tutto inutili attraverso tutti gli elementi trovati in questo codice; la variabile "classlist" e foreach attraverso "namespacelist" non forniscono funzionalità diverse dal ritorno a "namespacelist"
TheXenocide,

10
Lo scopo di un esempio di codice @TheXenocide non è sempre inteso a mostrare il modo "migliore" di scrivere il codice, ma a comunicare chiaramente come viene fatto qualcosa.
Ryan Farley,

4
Lo stavo solo sottolineando per motivi di educazione; è nostra responsabilità fare in modo che le persone materiali imparino dal miglior esempio possibile piuttosto che rischiare un cattivo esempio che influenza negativamente la comprensione. Non sto dicendo questo in particolare è dannoso, ma non sono d'accordo con il sentimento
TheXenocide,

4
Voto una risposta se non è utile alla domanda che è stata posta. Il suggerimento che vedi mentre passi con il mouse sul pulsante di voto su / giù dice "Questo è stato utile". La decisione di votare su / giù una risposta, per me, è se sia stato utile o meno rispondere alla domanda posta.
Ryan Farley,

3
L'unica cosa che hai usato con due elenchi e due iterazioni mi ha aiutato a rallentarmi cercando di capire il motivo per cui hai usato due elenchi e non hai semplicemente aggiunto direttamente alla classlistprima iterazione sul asm.GetTypes()risultato.
ProfK,

20

Per uno specifico Assembly, 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: il progetto deve fare riferimento all'assemblaggio


12

Ecco una correzione per gli errori LoaderException che probabilmente troverai se uno dei tipi sublass un tipo in un altro 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);
}

Ciò dovrebbe aiutare con i tipi di caricamento definiti in altri assiemi.

Spero che aiuti!


Certo sembra utile, e meno utile e meno confuso del codice di Ryan Farley anche senza pensarci.
ProfK,

Per un po 'mi hai anche confuso. Posso solo supporre che la Assembly aroba rappresenti la normale elaborazione che potrebbe causare il verificarsi di questo evento. Non vedo alcuna utilità anell'aiutare con LoaderExceptionerrori. Ho ragione?
ProfK,

9

Non sarai in grado di ottenere tutti i tipi in uno spazio dei nomi, perché uno spazio dei nomi può collegare più assembly, ma puoi ottenere tutte le classi in un assembly e verificare se appartengono a quello spazio dei nomi.

Assembly.GetTypes()funziona sull'assembly locale oppure è possibile caricare prima un assembly, quindi richiamarlo GetTypes().


2
+1 per la risposta corretta. AppDomain.CurrentDomain.GetAssembliespuò essere d'aiuto.
nawfal,

... e poi passaci attraverso, filtrando quelli che non corrispondono allo spazio dei nomi.
TJ Crowder,

OP ha specificamente chiesto "classi in uno spazio dei nomi", mentre ciò ti dà "tipi in un assembly" - quindi questa risposta è incompleta. La risposta corretta è probabilmente questa , che elenca solo le classi, da tutti gli assembly.
mindplay.dk

6

Proprio come la risposta di @aku, ma usando i metodi di estensione:

string @namespace = "...";

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

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

5

Ottieni tutte le classi per parte del nome dello spazio dei nomi in una sola riga:

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

3

Gli spazi dei nomi sono in realtà piuttosto passivi nella progettazione del runtime e servono principalmente come strumenti organizzativi. Il nome completo di un tipo in .NET è costituito dallo spazio dei nomi e da Class / Enum / Etc. combinato. Se si desidera solo passare attraverso un assembly specifico, è sufficiente scorrere i tipi restituiti dall'assembly. GetExportedTypes () verifica il valore di tipo. Namespace . Se si stesse tentando di esaminare tutti gli assembly caricati nell'AppDomain corrente, ciò implica l'utilizzo di 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 

Di cosa si tratta AttributeClassil nome MustHaveAttributes? Non vedo nulla relativo al test se una classe ha attributi o meno. Questo è più confuso che utile.
ProfK,

1

Abbastanza semplice

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

E semplicemente non risponde alla domanda. Tutto ciò che sta facendo è ottenere un elenco di tutti i tipi in un singolo assembly, indipendentemente da un determinato spazio dei nomi.
Ian
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.