Отримання всіх типів у просторі імен за допомогою відображення


268

Як ви отримуєте всі класи в просторі імен через відображення в C #?


Ви можете відредагувати своє запитання ... підтекстне питання є більш комунікативним, ніж "Простір імен у C #"
Gishu

Ви можете подивитися тут . Є 2 різних зразки.
Fatih GÜRDAL

Відповіді:


316

Наступний код друкує назви класів у визначених 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, здається, ледачий навантаження?
Харві

@Harvey Чи має .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;
}

Примітка. Вищенаведений код ілюструє, що відбувається. Якщо ви його реалізували, може бути використана спрощена версія:

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" і пропонують через "namespacelist" не забезпечують функціональних можливостей, відмінних від повернення "namespacelist"
TheXenocide,

10
@TheXenocide мета вибірки коду не завжди має на меті показати "найкращий" спосіб написання коду, але чітко передати, як щось робиться.
Райан Фарлі,

4
Я просто вказував це заради освіти; наша відповідальність полягає в тому, щоб зробити матеріал, який люди вчаться на найкращому прикладі, а не ризикувати поганим прикладом, який негативно впливає на розуміння. Я не кажу, що це, зокрема, згубно, але я не погоджуюся з настроями
TheXenocide

4
Я голосую відповідь вниз, якщо це не корисно з питання, яке було задано. Підказка, яку ви бачите при наведенні на кнопку голосування вгору / вниз, говорить "Це було корисно". Для мене рішення про те, щоб проголосувати вгору / вниз, відповідати, чи це було корисно у відповіді на поставлене питання.
Райан Фарлі

3
Єдине, що вам допомогло з використанням двох списків та двох ітерацій, - це сповільнити мене, намагаючись з’ясувати, чому ви використовували два списки, а не просто додавали прямо до classlistпершої ітерації над asm.GetTypes()результатом.
ПрофК

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

Це повинно допомогти для типів завантаження, визначених в інших збірках.

Сподіваюся, що це допомагає!


Звичайно, виглядає корисною, менш корисною і менш заплутаною, ніж код Райана Фарлі, навіть не замислюючись над цим.
ПрофК

Ти теж мене на деякий час розгубила. Я все ще можу лише здогадуватися, що Assembly aматеріал являє собою звичайну обробку, яка може призвести до запуску цієї події. Я не бачу ніякої користі aв допомозі з LoaderExceptionпомилками. Маю рацію?
ПрофК

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все? Я не бачу нічого, що стосується тестування того, має клас чи атрибути. Це більше заплутано, ніж корисно.
ПрофК

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.