繁体   English   中英

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

[英]Get all derived types of a type

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

  1. 获取使用过的程序集中的所有类型
  2. 用所有这些类型检查我的类型,如果它是“IsAssignable”

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

曾经使用这个 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();

细节:

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

我很确定您建议的方法将是查找所有派生类型的更简单方法。 父类不存储任何关于它们的子类是什么的信息(如果它们这样做会很愚蠢),这意味着无法避免在这里搜索所有类型。

唯一的建议是使用Type.IsSubclassOf方法而不是Type.IsAssignable来检查特定类型是否派生自另一个。 不过,也许您需要使用Type.IsAssignable是有原因的(例如,它适用于接口)。

如果是这种情况,您可以挤出的唯一优化是使用Assembly.GetExportedTypes()仅检索公开可见的类型。 除此之外,没有办法加快速度。 LINQ 可能有助于提高可读性,但不会提高性能。

您可以做一些短路以避免对IsAssignableFrom的不必要调用,根据 Reflector 的说法,这是相当昂贵的调用,方法是首先测试所讨论的类型是否属于必需的“类”。 也就是说,您只搜索类,测试枚举或数组的“可分配性”是没有意义的。

假设 baseType 包含您要检查的 System.Type 对象,并且 matchType 包含具有当前迭代类型的 System.Type 对象(通过 foreach 循环或其他方式):

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

matchType.IsSubclassOf(baseType)

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

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

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

我认为没有更好或直接的方法。

更好:使用IsSubclassOf而不是IsAssignable

我最终使用了最佳答案给出的代码。 唯一的问题是我希望代码更具可读性,所以我写了基本相同的东西,但改为这样:

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 ),所以我也排除了派生抽象类。

如果您只是对浏览感兴趣,那么 .NET Reflector 可以做到这一点。 但是,这并不是真正可行的事情。 您想要当前加载的程序集中的所有类型吗? 执行程序集引用的程序集? 有许多不同的方法来获取类型列表,并且编写一些可以解释(并提供选项)的东西将是一个相当大的成本和相对较低的收益。

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

只需在开始时创建派生类型的静态字典并使用它进行查找。 例如。 public static Dictionay<Type, Type[]> DerivedTypes { get;set; } 其中 Type 是您想要包含在搜索中的任何类型,Type[ public static Dictionay<Type, Type[]> DerivedTypes { get;set; }是派生类型的列表。 在应用程序启动时填写字典并在应用程序的整个生命周期中使用它。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM