【问题标题】:Get all User-Created Classes in AppDomain.CurrentDomain获取 AppDomain.CurrentDomain 中所有用户创建的类
【发布时间】:2012-06-04 12:49:07
【问题描述】:

我想遍历我在项目中添加的所有类

Assembly[] foo = AppDomain.CurrentDomain.GetAssemblies();

foreach(Assembly a in foo)
{                
    foreach(Type t in a.GetTypes())
    {

    }
}

这是我尝试过的,但我想排除 .net 提供的程序集,例如“mscorlib”

【问题讨论】:

    标签: c# reflection .net-assembly


    【解决方案1】:

    如果所有程序集都有一个共同的前缀(如果您有一个或多或少唯一的前缀),一个常见的解决方案是按名称过滤程序集。

    var foo = AppDomain.CurrentDomain.GetAssemblies()
                                     .Where(a=>a.FullName.StartsWith("MyProject."));
    

    如果您只对某些特定类型感兴趣,请考虑为您的类使用attributes,甚至在汇编级别添加一个。

    示例:

    创建一个属性:

    [AttributeUsage(AttributeTargets.Assembly)]
    public class MyAssemblyAttribute : Attribute { }
    

    将以下内容添加到您的 AssemblyInfo.cs:

    [assembly: MyAssemblyAttribute()]
    

    并过滤您正在查看的程序集:

    var foo = AppDomain.CurrentDomain
                       .GetAssemblies()
                       .Where(a => a.GetCustomAttributes(typeof(MyAssemblyAttribute), false).Any());
    

    您还会发现at this question 很有趣。在one answer 中建议检查每个程序集的完全限定名称,但这很繁琐,例如:

    //add more .Net BCL names as necessary
    var systemNames = new HashSet<string>
    {
        "mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
        "System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
        ...
    };
    
    var isSystemType = systemNames.Contains(objToTest.GetType().Assembly.FullName); 
    

    标记您的程序集(按名称或属性)总是比尝试识别哪些是 .Net 框架的一部分更容易。

    【讨论】:

    • 最好标记您自己的程序集,因为您可能不想要任何第三方程序集。 .NET 框架程序集可能不是您在项目中无法控制的唯一代码程序集。您还希望创建属性internal 并确保它仅对您的其他程序集公开。这样,您未指定的其他程序集就无法使用您的属性。
    • 还有办法找到所有使用特定类型的类型吗?例如,我想要所有类型为 StringBuilder 的类型。
    • 不使用属性标记它们!
    • @Jan 是的。这个有可能。但是提出一个新问题。
    • 属性使用是个好主意!,从字符串操作开始最容易出错。
    【解决方案2】:

    在我的一个项目中,我需要一个用作业务对象的类列表。这些类始终是用户创建的类型,但可以在引用的程序集中。它们不实现特定的接口,也不从特定的基类派生,也没有独特的属性。

    这是我用来过滤有用类型的代码:

    return
        type.IsClass && // I need classes
        !type.IsAbstract && // Must be able to instantiate the class
        !type.IsNestedPrivate && // Nested private types are not accessible
        !type.Assembly.GlobalAssemblyCache && // Excludes most of BCL and third-party classes
        type.Namespace != null && // Yes, it can be null!
        !type.Namespace.StartsWith("System.") && // EF, for instance, is not in the GAC
        !type.Namespace.StartsWith("DevExpress.") && // Exclude third party lib
        !type.Namespace.StartsWith("CySoft.Wff") && // Exclude my own lib
        !type.Namespace.EndsWith(".Migrations") && // Exclude EF migrations stuff
        !type.Namespace.EndsWith(".My") && // Excludes types from VB My.something
        !typeof(Control).IsAssignableFrom(type) && // Excludes Forms and user controls
        type.GetCustomAttribute<CompilerGeneratedAttribute>() == null && // Excl. compiler gen.
        !typeof(IControllerBase).IsAssignableFrom(type); // Specific to my project
    

    由于我的用户类型不在 GAC 中,!type.Assembly.GlobalAssemblyCache 在排除大多数 BCL(框架库)类型和一些第三方内容方面做得很好。

    这不是无懈可击的,但我的情况很好。您很可能需要根据自己的需要对其进行调整。

    【讨论】:

      【解决方案3】:

      检查 Type in inner loop 的以下属性。

      t.GetType().Namespace == "System"
      t.GetType().Namespace.StartsWith("System")
      t.GetType().Module.ScopeName == "CommonLanguageRuntimeLibrary"
      

      【讨论】:

      • 那行不通,因为我可以轻松地在 System 命名空间中定义类型。
      • 但我认为 ScopeName 属性会有所帮助。
      • @Romil 否。并非所有类型的 .Net 框架都是 mscorlib 的一部分。所以 ScopeName 并不总是 CommonLanguageRuntimeLibrary。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-05-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多