Yansıma yoluyla bir ad alanındaki tüm türleri alma


Yanıtlar:


317

Aşağıdaki kod namespace, geçerli derlemede tanımlanan sınıftaki adları yazdırır .
Diğer adamların işaret ettiği gibi, farklı modüller arasında bir ad alanı dağıtılabilir, bu yüzden önce montajların bir listesini almanız gerekir.

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'un dediği gibi, birden fazla montajda aynı ad alanına sahip olabilirsiniz (örneğin System.Collections.Generic). Zaten yüklü değilse, tüm bu montajları yüklemeniz gerekecektir. Tam bir cevap için:

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

Diğer etki alanlarının sınıflarını istemiyorsanız, bu işe yaramalıdır. Tüm alan adlarının bir listesini almak için bu bağlantıyı izleyin .


1
iyi çalışıyor - küçük bir hatırlatma: " && t.Namespace == @namespace" - kaldırmaya çalıştım hangi ofcause bana tüm .net meclisleri verdi :-)
Netsi1964

Netsi1964 @ kaldırmak eğer && t.Namespace == @namespacetüm almak sınıfları arasında tüm meclisleri .net de dâhil. GetAssembliessize tüm montajları GetAssemblies().SelectMany(t => t.GetTypes())verecek ve tüm montajlardan tüm türleri (sınıflar, yapılar vb.) verecektir.
nawfal

DotNet Core 2.2'ye (2.1'den) yükseltme yaptım ve bu kod benim özel montaj için çalışmayı durdurdu. İstediğim montaj kodun herhangi bir yerinde referans değildi bu yüzden yüklü değildi! 2.1 yılında yüklendi, ama 2.2 tembel yükleme var gibi görünüyor?
Harvey

@Harvey .NET Core'da başlamak için bir uygulama alanı var mı?
nawfal

@nawfal Evet. Bu kod daha önce 2.1'de çalışıyordu. İyi Assembly.Load(nameof(NameOfMyNamespace))çalışarak kullanarak bir montajın yüklenmesini zorladığımı buldum .
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: Yukarıdaki kod neler olup bittiğini göstermektedir. Uygulansaydınız, basitleştirilmiş bir sürüm kullanılabilir:

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
Kötü olmaya çalışmıyorum, ama tamamen gereksiz bir liste ve bu kodda bulunan tüm öğeleri aracılığıyla yineleme; "classlist" değişkeni ve "namespacelist" üzerinden foreach, "namespacelist" i döndürmekten farklı bir işlevsellik sağlamaz
TheXenocide

10
Bir kod örneğinin amacı @TheXenocide her zaman kod yazmanın "en iyi" yolunu göstermek değil, bir şeyin nasıl yapıldığını açıkça anlatmak anlamına gelir.
Ryan Farley

4
Sadece eğitim uğruna işaret ediyordum; insanların, anlayışı olumsuz etkileyen kötü bir örneği riske atmak yerine, yapabileceğimiz en iyi örnekten öğrenmelerini sağlamak bizim sorumluluğumuzdur. Ben özellikle bu zararlı olduğunu söylemiyorum, ama duygu ile aynı fikirde değilim
TheXenocide

4
Sorulan soruya yardımcı olmazsa bir cevabı oyluyorum. Yukarı / aşağı oy düğmesinin üzerine geldiğinizde ipucu "Bu yardımcı oldu" yazıyor. Bir cevabı yukarı / aşağı oylama kararı, benim için, sorulan soruyu cevaplamanın faydalı olup olmadığıdır.
Ryan Farley

3
İki listeleri ve yardımcı iki tekrarı kullanılarak yalnızca şey iki listeyi kullanılan ve sadece düz eklemek vermedi sadece nedenini anlamaya çalışıyorum beni yavaşlatmak için oldu classlistüzerinde birinci tekrar asm.GetTypes()sonucu.
ProfK

20

Belirli bir Assembly, NameSpace ve ClassName için:

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

Not: Proje montajı referans almalıdır


12

Aşağıda, türlerden birinin başka bir derlemede bir tür alt sınıfının olup olmadığını bulacağınız LoaderException hataları için bir düzeltme verilmiştir:

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

Bu, diğer montajlarda tanımlanan yükleme türlerine yardımcı olacaktır.

Umarım yardımcı olur!


Tabii ki düşünmeden bile Ryan Farley'in kodundan daha yararlı ve daha az yardımcı ve daha az kafa karıştırıcı görünüyor.
ProfK

Yine de bir süredir kafam karıştı. Yine de sadece Assembly abu olayın tetiklenmesine neden olabilecek normal işlemleri temsil ettiğini tahmin edebiliyorum . aHatalara yardımcı olmanın faydasını görmüyorum LoaderException. Haklı mıyım?
ProfK

9

Bir ad alanında tüm türleri alamazsınız, çünkü bir ad alanı birden fazla montajı köprüleyebilir, ancak bir montajdaki tüm sınıfları alabilir ve bu ad alanına ait olup olmadıklarını kontrol edebilirsiniz.

Assembly.GetTypes()yerel derlemede çalışır veya önce bir derleme yükleyebilir ve sonra arayabilirsiniz GetTypes().


2
Doğru cevap için +1. AppDomain.CurrentDomain.GetAssembliesyardımcı olabilir.
nawfal

... ve ad alanı ile uyuşmayanları filtreleyerek aralarında dolaşın.
TJ Crowder

OP özellikle "bir ad alanındaki sınıfları" istedi, ancak bu size "bir derlemede türler" getirir - bu nedenle bu yanıt eksiktir. Doğru cevap muhtemelen bu bir bütün meclisleri dışında, sadece sınıfları sıralamaktadır.
mindplay.dk

6

Tıpkı @aku yanıtı gibi, ancak uzantı yöntemlerini kullanarak:

string @namespace = "...";

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

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

5

Tüm sınıfları Ad Alanı adının bir bölümüne göre tek bir satırda alın:

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

3

Ad alanları aslında çalışma zamanının tasarımında oldukça pasiftir ve öncelikle organizasyonel araçlar olarak hizmet eder. .NET'te bir türün Tam Adı, Ad Alanı ve Sınıf / Enum / Etc'den oluşur. Kombine. Yalnızca belirli bir montajdan geçmek istiyorsanız, montaj tarafından döndürülen türler arasında dolaşmanız yeterlidir. Türün değerini denetleyen GetExportedTypes () . Ad alanı . Geçerli AppDomain'de yüklü olan tüm derlemeleri gözden geçirmeye çalışıyorsanız, AppDomain.CurrentDomain'i kullanmayı gerektirir. 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 

AttributeClassAdı ne MustHaveAttributeshakkında? Bir sınıfın nitelikleri olup olmadığını test etmeyle ilgili hiçbir şey görmüyorum. Bu yardımcı olmaktan daha kafa karıştırıcı.
ProfK

1

Oldukça basit

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

Ve oldukça basit bir şekilde soruyu cevaplamıyor. Tek yapmanız gereken, belirli bir ad alanına bakılmaksızın, tek bir derlemedeki tüm türlerin bir listesini almaktır.
Ian
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.