How to find all classes that implements a generic abstract class using reflection in C#?

  • A+

I have a c# class that looks like this

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

I extend this class something like this

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

I need to use reflection to find all classes that extend the Listener<> base class.

I tried the following

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(); 

But that does not return anything. This condition returns false all the time listener.GetGenericTypeDefinition() == typeof(Listener<>)

How can I correctly find all the classes that extend the Listener<> base class?


Start by building up the infrastructure you need: put more tools in your toolbox, and then use those tools.

You want to list all the base types of a type, so list all the base types of a type:

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

Now we have a useful tool in our toolbox.

We have a type in hand. We wish to know if something is true of any of its base types. Therefore we should be using Any:

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

Now we have another useful tool.

We want to know if a particular type is a particular generic:

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

We want to know if a particular type is a listener:

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

Now we have the tools we need.

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

See how much easier the query is to read when you build up the tools you need one at a time? What do we want to know? If any base type is a listener. So how does the code read? "where type any base type is listener" -- the code reads like a description of what it does.


:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: