如何使用C#中的reflection查找实现generics抽象类的所有类?

我有一个看起来像这样的c#

 public abstract class Listener where T : Event { public abstract void Handle(T _event); } 

我把这个类延伸到这个类

 public class SendWelcomeEmail : Listener { public override void Handle(UserWasCreated _event) { //... } } 

我需要使用reflection来查找扩展Listener基类的所有类。

我尝试了以下内容

 var listeners = AppDomain.CurrentDomain.GetAssemblies() .SelectMany(assembly => assembly.GetTypes()) .Where(x => x.IsClass && !x.IsInterface) .Where(listener => !listener.IsAbstract && listener.IsGenericType && listener.GetGenericTypeDefinition() == typeof(Listener)) .ToList(); 

但这并不会带来任何回报。 这个条件一直返回false listener.GetGenericTypeDefinition() == typeof(Listener)

如何才能正确找到扩展Listener基类的所有类?

首先构建您需要的基础架构:在工具箱中放置更多工具,然后使用这些工具。

您想列出类型的所有基类型,因此列出类型的所有基类型:

 static class Extensions { public static IEnumerable BaseTypes(this Type type) { Type t = type; while (true) { t = t.BaseType; if (t == null) break; yield return t; } } } 

现在我们的工具箱中有一个有用的工具。

我们有一个类型。 我们想知道它的任何基类型是否都有。 因此我们应该使用Any

 static bool AnyBaseType(this Type type, Func predicate) => type.BaseTypes().Any(predicate); 

现在我们有另一个有用的工具。

我们想知道特定类型是否是特定的generics:

 static bool IsParticularGeneric(this Type type, Type generic) => type.IsGenericType && type.GetGenericTypeDefinition() == generic; 

我们想知道某个特定类型是否是一个监听器:

 static bool IsListener(Type type) => type.IsParticularGeneric(typeof(Listener<>)); 

现在我们拥有了我们需要的工具。

 var listeners = from assembly in AppDomain.CurrentDomain.GetAssemblies() from type in assembly.GetTypes() where type.AnyBaseType(IsListener) select type; 

当您构建一次需要的工具时,查看查询的读取容易程度如何? 我们想知道什么? 如果任何基类型是监听器 。 那么代码是如何读取的? “任何基类型都是监听器的类型” – 代码读起来就像它的作用描述。

你可以找出任何基类型是一个Listener<> ,通过递归检查是目标类型IsInheritedFrom它:

 public static class Extension { public static bool IsInheritedFrom(this Type type, Type Lookup) { var baseType = type.BaseType; if (baseType == null) return false; if (baseType.IsGenericType && baseType.GetGenericTypeDefinition() == Lookup) return true; return baseType.IsInheritedFrom(Lookup); } } var lookup = typeof(Listener<>); var listeners = AppDomain.CurrentDomain.GetAssemblies() .SelectMany(assembly => assembly.GetTypes()) .Where(x => x.IsClass && !x.IsAbstract && x.IsInheritedFrom(lookup)) .ToList();