รับทุกประเภทใน namespace ผ่านการสะท้อน


269

คุณจะรับคลาสทั้งหมดในเนมสเปซผ่านการสะท้อนใน C # ได้อย่างไร


คุณสามารถแก้ไขคำถามของคุณได้หรือไม่ ... คำถามคำบรรยายเป็นการสื่อสารมากกว่า 'Namespace ใน C #'
Gishu

คุณสามารถดูที่นี่ มี 2 ​​ตัวอย่างที่แตกต่างกัน
Fatih GÜRDAL

คำตอบ:


317

รหัสต่อไปนี้พิมพ์ชื่อของคลาสในที่ระบุ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" - ซึ่งเป็นสาเหตุให้ฉันทั้งหมด . แอสเซมบลีสุทธิ :-)
Netsi1964

@ Netsi1964 หากคุณลบ&& t.Namespace == @namespaceคุณจะได้รับคลาสทั้งหมดของชุดประกอบทั้งหมดรวมถึง. net GetAssembliesจะให้คุณประกอบทั้งหมดและGetAssemblies().SelectMany(t => t.GetTypes())จะให้ทุกประเภท (ชั้นเรียน structs ฯลฯ ) จากการประกอบทั้งหมด
nawfal

ฉันอัพเกรดเป็น DotNet Core 2.2 (จาก 2.1) และรหัสนี้หยุดทำงานสำหรับแอสเซมบลีเฉพาะของฉัน แอสเซมบลีที่ฉันต้องการไม่ได้อ้างอิงในรหัสใด ๆ ดังนั้นจึงไม่โหลด ใน 2.1 มันถูกโหลด แต่ 2.2 ดูเหมือนว่าจะมีการโหลดขี้เกียจ?
ฮาร์วีย์

@Harvey. NET Core มี appdomain เริ่มต้นด้วยหรือไม่
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" และ foreach ผ่าน "namespacelist" ไม่สามารถใช้งานได้แตกต่างไปจากการส่งกลับ "namespacelist"
TheXenocide

10
@TheXenocide จุดประสงค์ของตัวอย่างโค้ดนั้นไม่ได้หมายถึงการแสดงวิธีการเขียนรหัสที่ดีที่สุดเสมอไป
Ryan Farley

4
ฉันแค่ชี้ให้เห็นเพื่อการศึกษา มันเป็นความรับผิดชอบของเราที่จะทำให้คนสำคัญเรียนรู้จากตัวอย่างที่ดีที่สุดที่เราสามารถทำได้แทนที่จะเสี่ยงกับตัวอย่างที่ไม่ดี ฉันไม่ได้พูดแบบนี้โดยเฉพาะเป็นอันตราย แต่ฉันไม่เห็นด้วยกับความเชื่อมั่น
TheXenocide

4
ฉันลงคะแนนคำตอบหากไม่เป็นประโยชน์กับคำถามที่ถาม คำใบ้ที่คุณเห็นเมื่อคุณเลื่อนเมาส์ไปเหนือปุ่มโหวตขึ้น / ลงจะบอกว่า "สิ่งนี้มีประโยชน์" การตัดสินใจว่าจะตอบคำถามขึ้น / ลงนั้นเป็นประโยชน์หรือไม่ในการตอบคำถามที่ถาม
Ryan Farley

3
สิ่งเดียวที่คุณใช้สองรายการและการทำซ้ำสองรายการช่วยให้ฉันช้าลงโดยพยายามคิดออกว่าทำไมคุณถึงใช้สองรายการและไม่เพียงเพิ่มลงไปclasslistในการทำซ้ำครั้งแรกของasm.GetTypes()ผลลัพธ์
ProfK

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

ที่ควรช่วยในการโหลดประเภทที่กำหนดไว้ในชุดประกอบอื่น ๆ

หวังว่าจะช่วย!


แน่นอนว่ามีประโยชน์และมีประโยชน์มากกว่าและสับสนน้อยกว่าโค้ดของ Ryan Farley แม้ว่าจะไม่ได้คิดก็ตาม
ProfK

คุณทำให้ฉันสับสนไปซักพักแล้ว ฉันยังคงคาดเดาได้เท่านั้นว่าAssembly aสิ่งต่าง ๆ นั้นแสดงถึงการประมวลผลปกติที่อาจทำให้เหตุการณ์นี้เริ่มทำงาน ฉันไม่เห็นประโยชน์aในการช่วยเหลือLoaderExceptionข้อผิดพลาด ฉันถูกไหม?
ProfK

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

จริง ๆ แล้ว Namespaces ค่อนข้างแฝงอยู่ในการออกแบบรันไทม์และใช้เป็นเครื่องมือขององค์กรเป็นหลัก ชื่อเต็มของประเภทใน. NET ประกอบด้วย Namespace และ Class / Enum / Etc รวม ถ้าคุณเพียงต้องการผ่านแอสเซมบลีเฉพาะคุณเพียงแค่วนรอบชนิดที่ส่งคืนโดยแอสเซมบลี GetExportedTypes ()ตรวจสอบค่าประเภท namespace หากคุณกำลังพยายามผ่านชุดประกอบทั้งหมดที่โหลดใน 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ทั้งหมดเกี่ยวกับ? ฉันไม่เห็นอะไรเกี่ยวข้องกับการทดสอบว่าคลาสมีคุณสมบัติหรือไม่ นี่คือความสับสนมากกว่าที่เป็นประโยชน์
ProfK

1

ค่อนข้างง่าย

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

และค่อนข้างง่ายที่จะไม่ตอบคำถาม ทั้งหมดนี้กำลังทำอยู่คือรับรายการทุกประเภทในแอสเซมบลีเดียวโดยไม่คำนึงถึงเนมสเปซใด ๆ
เอียน
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.