通过反射获取命名空间中的所有类型

Getting all types in a namespace via reflection

提问人: 提问时间:9/17/2008 最后编辑:H.B. 更新时间:1/12/2019 访问量:209556

问:

如何通过 C# 中的反射获取命名空间中的所有类?

C# .NET 反射 命名空间

评论

0赞 Gishu 9/17/2008
你能编辑你的问题吗?潜台词问题比“C#中的命名空间”更具交际性
0赞 Fatih GÜRDAL 11/15/2016
你可以看这里。有 2 个不同的样本。

答:

34赞 Ryan Farley 9/17/2008 #1
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);
}

评论

1赞 Gishu 9/17/2008
注意:只要输入要查找的程序集和 NS,就可以执行此操作。类型可以在多个程序集中定义,并且属于同一个 NS。
10赞 TheXenocide 9/19/2008
我并不是要刻薄,但是在此代码中,有一个完全不必要的列表和遍历所有找到的项;“classlist”变量和 foreach 通过“namespacelist”提供与返回“namespacelist”不同的功能
12赞 Ryan Farley 9/19/2008
@TheXenocide代码示例的目的并不总是要展示编写代码的“最佳”方式,而是清楚地传达某事是如何完成的。
4赞 ProfK 10/26/2014
使用两个列表和两次迭代的唯一帮助是减慢了我的速度,试图弄清楚为什么你使用两个列表,而不仅仅是在第一次迭代中直接添加结果。classlistasm.GetTypes()
3赞 Juho 11/6/2018
当您只有一个数据列表要处理时,这里有两个列表是糟糕的代码。它不会使任何事情更清晰,并且会鼓励阅读它的初学者养成不良的编码习惯。
10赞 FlySwat 9/17/2008 #2

您将无法获取命名空间中的所有类型,因为命名空间可以桥接多个程序集,但您可以获取程序集中的所有类并检查它们是否属于该命名空间。

Assembly.GetTypes()适用于本地程序集,也可以先加载程序集,然后再调用它。GetTypes()

评论

2赞 nawfal 5/12/2013
+1 表示正确答案。 可能会有所帮助。AppDomain.CurrentDomain.GetAssemblies
0赞 T.J. Crowder 6/29/2015
...然后遍历它们,过滤掉与命名空间不匹配的那些。
0赞 mindplay.dk 4/14/2020
OP 特别要求“命名空间中的类”,而这会让你“在程序集中键入”——所以这个答案是不完整的。正确答案可能是这个,它仅枚举所有程序集中的类。
346赞 aku 9/17/2008 #3

以下代码打印当前程序集中定义的指定类的名称。
正如其他人所指出的,命名空间可以分散在不同的模块之间,因此您需要先获取程序集列表。
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));
3赞 TheXenocide 9/17/2008 #4

命名空间实际上在运行时的设计中是相当被动的,主要用作组织工具。.NET 中类型的全名由 Namespace 和 Class/Enum/Etc. 组合而成。如果只想遍历特定的程序集,则只需遍历程序集返回的类型即可。GetExportedTypes() 检查 type 的值。命名空间。如果尝试遍历当前 AppDomain 中加载的所有程序集,则需要使用 AppDomain.CurrentDomain。GetAssemblies()

14赞 tsimon 9/17/2008 #5

下面是 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);
}

这应该有助于加载其他程序集中定义的类型。

希望对您有所帮助!

评论

0赞 ProfK 10/26/2014
当然看起来很有帮助,即使不考虑它,也比 Ryan Farley 的代码更有用、更不令人困惑。
0赞 ProfK 10/26/2014
不过,你也确实让我困惑了一段时间。我仍然只能猜测这些东西代表了可能导致此事件触发的正常处理。我认为帮助解决错误是没有用的。我说得对吗?Assembly aaLoaderException
2赞 Yordan Georgiev 4/18/2009 #6
//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 

评论

0赞 ProfK 10/26/2014
这个名字到底是怎么回事?我看不出任何与测试类是否具有属性有关的内容。这更令人困惑,而不是有帮助。AttributeClassMustHaveAttributes
6赞 JoanComasFdz 1/9/2013 #7

就像@aku答案一样,但使用扩展方法:

string @namespace = "...";

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

types.ForEach(t => Console.WriteLine(t.Name));
112赞 nawfal 5/12/2013 #8

正如 FlySwat 所说,您可以在多个程序集中拥有相同的命名空间(例如 )。如果尚未加载所有这些程序集,则必须加载它们。因此,对于完整的答案:System.Collections.Generic

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

除非您想要其他域的类,否则这应该有效。要获取所有域的列表,请点击此链接。

评论

1赞 Netsi1964 7/10/2014
工作正常 - 一个小提醒:我试图删除“” - 这给了我所有 .net 程序集:-)&& t.Namespace == @namespace
0赞 nawfal 7/10/2014
@Netsi1964如果删除,则将获得所有程序集的所有,包括 .net。 将为您提供所有程序集,并将提供所有程序集的所有类型(类、结构等)。&& t.Namespace == @namespaceGetAssembliesGetAssemblies().SelectMany(t => t.GetTypes())
0赞 harvzor 8/26/2019
我从 2.1 升级到 DotNet Core 2.2,此代码停止适用于我的特定程序集。我想要的程序集没有在代码中的任何位置引用,所以没有加载!在 2.1 中它被加载了,但 2.2 似乎有延迟加载?
0赞 nawfal 8/26/2019
@Harvey .NET Core 是否首先具有 appdomain?
0赞 harvzor 8/26/2019
@nawfal是的。此代码以前在 2.1 中有效。我发现我通过使用工作来强制加载程序集。Assembly.Load(nameof(NameOfMyNamespace))
5赞 Ivo Stoyanov 12/22/2014 #9

在一行中按命名空间名称的一部分获取所有类:

var allClasses = Assembly.GetExecutingAssembly().GetTypes().Where(a => a.IsClass && a.Namespace != null && a.Namespace.Contains(@"..your namespace...")).ToList();
27赞 JWP 1/19/2016 #10

对于特定的 Assembly、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();

注意:项目必须引用程序集

0赞 Antonio Lopes 3/1/2016 #11

很简单

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

评论

1赞 Ian 3/4/2020
而且干脆不回答这个问题。所有这一切都是在单个程序集中获取所有类型的列表,而不考虑任何特定的命名空间。