Mendapatkan semua tipe dalam namespace melalui refleksi

269

Bagaimana Anda mendapatkan semua kelas di namespace melalui refleksi di C #?

HB
sumber
dapatkah Anda mengedit pertanyaan Anda ... pertanyaan subteksnya lebih komunikatif daripada 'Namespace in C #'
Gishu
Anda bisa melihat di sini . Ada 2 sampel berbeda.
Fatih GÜRDAL

Jawaban:

317

Kode berikut mencetak nama-nama kelas yang ditentukan namespaceditentukan dalam majelis saat ini.
Seperti yang ditunjukkan orang lain, namespace dapat tersebar di antara modul yang berbeda, jadi Anda harus mendapatkan daftar rakitan terlebih dahulu.

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
sumber
83

Seperti yang dikatakan FlySwat, Anda dapat memiliki namespace yang sama yang mencakup banyak majelis (misalnya System.Collections.Generic). Anda harus memuat semua rakitan itu jika belum dimuat. Jadi untuk jawaban yang lengkap:

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

Ini akan berfungsi kecuali jika Anda ingin kelas domain lain. Untuk mendapatkan daftar semua domain, ikuti tautan ini.

nawfal
sumber
1
berfungsi dengan baik - pengingat kecil: Saya mencoba untuk menghapus " && t.Namespace == @namespace" - yang mana karena memberi saya semua .net rakitan :-)
Netsi1964
@ Netsi1964 jika Anda menghapus && t.Namespace == @namespaceAnda mendapatkan semua kelas dari semua majelis , termasuk. Net. GetAssembliesakan memberi Anda semua majelis, dan GetAssemblies().SelectMany(t => t.GetTypes())akan memberikan semua jenis (kelas, struct dll) dari semua majelis.
nawfal
Saya memutakhirkan ke DotNet Core 2.2 (dari 2.1) dan kode ini berhenti berfungsi untuk perakitan khusus saya. Perakitan yang saya inginkan tidak dirujuk di mana pun dalam kode sehingga tidak dimuat! Dalam 2.1 itu dimuat, tetapi 2,2 tampaknya memuat malas?
Harvey
@ Harvey Apakah .NET Core memiliki appdomain untuk memulai?
nawfal
@nawfal Ya. Kode ini berfungsi sebelumnya di 2.1. Saya menemukan bahwa saya memaksa memuat perakitan dengan menggunakan Assembly.Load(nameof(NameOfMyNamespace))bekerja dengan baik.
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: Kode di atas menggambarkan apa yang terjadi. Jika Anda ingin menerapkannya, versi yang disederhanakan dapat digunakan:

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
sumber
9
Saya tidak berusaha menjadi kejam, tetapi ada daftar dan iterasi yang sama sekali tidak perlu melalui semua item yang ditemukan dalam kode ini; variabel "classlist" dan foreach melalui "namespacelist" tidak memberikan fungsi yang berbeda dengan mengembalikan "namespacelist"
TheXenocide
10
@TheXenocide tujuan dari contoh kode tidak selalu dimaksudkan untuk menunjukkan cara "terbaik" untuk menulis kode, tetapi untuk secara jelas menyampaikan bagaimana sesuatu dilakukan.
Ryan Farley
4
Saya baru saja menunjukkannya demi pendidikan; itu adalah tanggung jawab kita untuk membuat materi yang orang pelajari dari contoh terbaik kita daripada mengambil risiko contoh buruk yang secara negatif mempengaruhi pemahaman. Saya tidak mengatakan ini secara khusus merugikan, tetapi saya tidak setuju dengan sentimen
TheXenocide
4
Saya memilih jawaban jika tidak membantu pertanyaan yang diajukan. Petunjuk yang Anda lihat saat Anda mengarahkan kursor ke tombol suara naik / turun mengatakan "Ini sangat membantu". Keputusan untuk memilih naik / turun jawaban, bagi saya, adalah apakah itu membantu atau tidak dalam menjawab pertanyaan yang diajukan.
Ryan Farley
3
Satu-satunya hal yang Anda gunakan dua daftar dan dua iterasi membantu adalah memperlambat saya mencoba mencari tahu mengapa Anda menggunakan dua daftar dan tidak hanya menambahkan langsung classlistpada iterasi pertama atas asm.GetTypes()hasilnya.
ProfK
20

Untuk Majelis tertentu, NameSpace dan 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();

Catatan: Proyek harus merujuk perakitan

John Peters
sumber
12

Berikut ini adalah perbaikan untuk kesalahan LoaderException yang mungkin Anda temukan jika salah satu dari jenis-jenis itu menutupi suatu jenis dalam rakitan lain:

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

Itu akan membantu dengan memuat jenis yang didefinisikan dalam majelis lain.

Semoga itu bisa membantu!

tsimon
sumber
Tentu terlihat membantu, dan kurang membantu dan kurang membingungkan daripada kode Ryan Farley bahkan tanpa memikirkannya
ProfK
Anda juga membuat saya bingung untuk sementara waktu. Saya masih hanya bisa menebak bahwa Assembly abarang - barang tersebut mewakili pemrosesan normal yang mungkin menyebabkan peristiwa ini memanas. Saya melihat tidak ada gunanya amembantu dengan LoaderExceptionkesalahan. Apakah saya benar?
ProfK
9

Anda tidak akan bisa mendapatkan semua tipe dalam namespace, karena namespace dapat menjembatani banyak majelis, tetapi Anda bisa mendapatkan semua kelas dalam sebuah majelis dan memeriksa untuk melihat apakah mereka termasuk dalam namespace itu.

Assembly.GetTypes()bekerja pada rakitan lokal, atau Anda dapat memuat rakitan terlebih dahulu kemudian memanggilnya GetTypes().

FlySwat
sumber
2
+1 untuk jawaban yang benar. AppDomain.CurrentDomain.GetAssembliesdapat membantu.
nawfal
... dan kemudian memutarnya, memfilter yang tidak cocok dengan namespace.
TJ Crowder
OP secara khusus meminta "kelas dalam ruang nama", sedangkan ini membuat Anda "mengetik dalam sebuah majelis" - jadi jawaban ini tidak lengkap. Jawaban yang benar mungkin adalah yang ini , yang menyebutkan kelas saja, dari semua majelis.
mindplay.dk
6

Sama seperti jawaban @aku, tetapi menggunakan metode ekstensi:

string @namespace = "...";

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

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

Dapatkan semua kelas dengan bagian nama Namespace hanya dalam satu baris:

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

Namespaces sebenarnya agak pasif dalam desain runtime dan berfungsi terutama sebagai alat organisasi. Nama lengkap tipe dalam .NET terdiri dari Namespace dan Class / Enum / Etc. digabungkan. Jika Anda hanya ingin melalui perakitan tertentu, Anda hanya akan mengulang jenis yang dikembalikan oleh perakitan. GetExportedTypes () memeriksa nilai tipe. Namespace . Jika Anda mencoba untuk melewati semua majelis yang dimuat di AppDomain saat ini, itu akan melibatkan penggunaan AppDomain.CurrentDomain. GetAssemblies ()

TheXenocide
sumber
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
sumber
Tentang apa AttributeClassnama itu MustHaveAttributes? Saya tidak melihat apa pun yang berkaitan dengan pengujian apakah suatu kelas memiliki atribut atau tidak. Ini lebih membingungkan daripada membantu.
ProfK
1

Cukup sederhana

Type[] types = Assembly.Load(new AssemblyName("mynamespace.folder")).GetTypes();
foreach (var item in types)
{
}
Antonio Lopes
sumber
Dan tidak menjawab pertanyaan itu. Semua ini dilakukan adalah mendapatkan daftar semua jenis dalam satu rakitan, terlepas dari namespace tertentu.
Ian