获取某个类型的所有派生类型

问题描述 投票:0回答:8

是否有更好的(性能更高或更漂亮的代码;)方法来查找类型的所有派生类型? 目前我正在使用类似的东西:

  1. 获取已用组件中的所有类型
  2. 检查我的类型与所有这些类型是否为“IsAssignable”

我想知道是否有更好的方法来做到这一点?

c# .net inheritance reflection
8个回答
107
投票

once使用这个Linq方法来获取从基类型B继承的所有类型:

    var listOfBs = (
                from domainAssembly in AppDomain.CurrentDomain.GetAssemblies()
                // alternative: from domainAssembly in domainAssembly.GetExportedTypes()
                from type in domainAssembly.GetTypes()
                where typeof(B).IsAssignableFrom(type)
                // alternative: && type != typeof(B)
                // alternative: && ! type.IsAbstract
                // alternative: where type.IsSubclassOf(typeof(B))
                select type).ToArray();

编辑:由于这似乎仍然得到更多的代表(因此更多的视图),让我添加一个流畅的版本和更多细节:

   var listOfBs = AppDomain.CurrentDomain.GetAssemblies()
                // alternative: .GetExportedTypes()
                .SelectMany(domainAssembly => domainAssembly.GetTypes())
                .Where(type => typeof(B).IsAssignableFrom(type)
                // alternative: => type.IsSubclassOf(typeof(B))
                // alternative: && type != typeof(B)
                // alternative: && ! type.IsAbstract
                ).ToArray();

详情:

  • 正如上述链接所述,此方法在每次调用时都使用反射。因此,当对同一类型重复使用该方法时, 通过加载一次,例如通过
    Lazy
    ,可能会提高效率。
  • 正如Anton建议的那样,也许你可以使用
    domainAssembly.GetExportedTypes()
    (微)优化它 仅检索公开可见的类型(如果这就是您所需要的)。
  • 正如Noldorin提到的那样,
    Type.IsAssignable
    也将获得原始(非派生)类型。 (
    Type.IsSubclassOf
    不会,但如果基本类型是接口,
    Type.IsSubclassOf
    将不起作用)。但当然,可以排除原始基类:
    && type != typeof(B)
  • 人们可能想要/需要检查具体实现的类,即忽略抽象类:
    && ! assemblyType.IsAbstract
    。 (请注意,所有接口都被认为是抽象的,请参阅MSDN。)
  • FWIW:正如乔恩·斯基特(Jon Skeet)在类似问题中建议的那样:“如果你需要处理泛型,那就更棘手了”。 快速搜索会返回一些建议,但可能还有更多,而且我没有检查它们(例如,为了正确性):
      获取实现特定开放泛型类型的所有类型
    • 获取通用接口的所有实现类型
    • 获取实现接口的所有类型

14
投票

唯一的建议是使用

Type.IsSubclassOf

方法而不是

Type.IsAssignable
来检查特定类型是否派生于另一个类型。尽管如此,也许您需要使用
Type.IsAssignable
(例如,它适用于接口)。
    


7
投票
Assembly.GetExportedTypes()

仅检索公开可见的类型(如果是这种情况)。除此之外,没有办法加快速度。 LINQ 可能有助于提高可读性,但不会提高性能。


您可以通过首先测试相关类型是否属于所需的“类”来进行一些短路,以避免不必要地调用

IsAssignableFrom

,根据 Reflector 的说法,这是相当昂贵的调用。也就是说,您仅搜索类,测试枚举或数组的“可分配性”是没有意义的。

    


5
投票

如果你想检查 matchType 是否是从 baseType 表示的类派生的,我会使用

matchType.IsSubclassOf(baseType)

如果你想检查 matchType 是否实现了由 baseType 表示的接口,我会使用

matchType.GetInterface(baseType.ToString(), false) != null

当然,我会将 baseType.ToString() 存储为全局变量,这样我就不需要一直调用它。由于您可能需要在有很多类型的上下文中使用它,因此您还可以考虑使用 System.Threading.Tasks.Parallel.ForEach-Loop 来迭代所有类型...


4
投票

更好:使用

IsSubclassOf

代替

IsAssignable
    


2
投票

var derived_types = new List<Type>(); foreach (var domain_assembly in AppDomain.CurrentDomain.GetAssemblies()) { var assembly_types = domain_assembly.GetTypes() .Where(type => type.IsSubclassOf(typeof(MyType)) && !type.IsAbstract); derived_types.AddRange(assembly_types); }

在我的例子中,我使用了
type.IsSubClassOf(MyType)

,因为我只想要派生类型,不包括上面提到的基类。我还需要派生类型不要是抽象的 (

!type.IsAbstract
),因此我也排除了派生抽象类。
    


1
投票

你想做什么?可能有更好(或至少更有效)的方法来实现它。


0
投票
public static Dictionay<Type, Type[]> DerivedTypes { get;set; }

其中 Type 是您想要包含在搜索中的任何类型 Type[] 是派生类型的列表。 当应用程序启动时填充字典并在应用程序的整个生命周期中使用它。

    

© www.soinside.com 2019 - 2024. All rights reserved.