Get all inherited classes of an abstract class

127,270

Solution 1

This is such a common problem, especially in GUI applications, that I'm surprised there isn't a BCL class to do this out of the box. Here's how I do it.

public static class ReflectiveEnumerator
{
    static ReflectiveEnumerator() { }

    public static IEnumerable<T> GetEnumerableOfType<T>(params object[] constructorArgs) where T : class, IComparable<T>
    {
        List<T> objects = new List<T>();
        foreach (Type type in 
            Assembly.GetAssembly(typeof(T)).GetTypes()
            .Where(myType => myType.IsClass && !myType.IsAbstract && myType.IsSubclassOf(typeof(T))))
        {
            objects.Add((T)Activator.CreateInstance(type, constructorArgs));
        }
        objects.Sort();
        return objects;
    }
}

A few notes:

  • Don't worry about the "cost" of this operation - you're only going to be doing it once (hopefully) and even then it's not as slow as you'd think.
  • You need to use Assembly.GetAssembly(typeof(T)) because your base class might be in a different assembly.
  • You need to use the criteria type.IsClass and !type.IsAbstract because it'll throw an exception if you try to instantiate an interface or abstract class.
  • I like forcing the enumerated classes to implement IComparable so that they can be sorted.
  • Your child classes must have identical constructor signatures, otherwise it'll throw an exception. This typically isn't a problem for me.

Solution 2

Assuming they are all defined in the same assembly, you can do:

IEnumerable<AbstractDataExport> exporters = typeof(AbstractDataExport)
    .Assembly.GetTypes()
    .Where(t => t.IsSubclassOf(typeof(AbstractDataExport)) && !t.IsAbstract)
    .Select(t => (AbstractDataExport)Activator.CreateInstance(t));

Solution 3

It may not be the elegant way but you can iterate all classes in the assembly and invoke Type.IsSubclassOf(AbstractDataExport) for each one.

Solution 4

typeof(AbstractDataExport).Assembly tells you an assembly your types are located in (assuming all are in the same).

assembly.GetTypes() gives you all types in that assembly or assembly.GetExportedTypes() gives you types that are public.

Iterating through the types and using type.IsAssignableFrom() gives you whether the type is derived.

Share:
127,270
trampi
Author by

trampi

Updated on July 08, 2022

Comments

  • trampi
    trampi almost 2 years

    I have an abstract class:

    abstract class AbstractDataExport
    {
            public string name;
            public abstract bool ExportData();
    }
    

    I have classes which are derived from AbstractDataExport:

    class XmlExport : AbstractDataExport
    {
        new public string name = "XmlExporter";
        public override bool ExportData()
        {
            ...
        }
    }
    class CsvExport : AbstractDataExport
    {
        new public string name = "CsvExporter";
        public override bool ExportData()
        {
            ...
        }
    }
    

    Is it possible to do something like this? (Pseudocode:)

    foreach (Implementation imp in Reflection.GetInheritedClasses(AbstractDataExport)
    {
        AbstractDataExport derivedClass = Implementation.CallConstructor();
        Console.WriteLine(derivedClass.name)
    }
    

    with an output like

    CsvExporter
    XmlExporter
    

    ?

    The idea behind this is to just create a new class which is derived from AbstractDataExport so i can iterate through all implementations automatically and add for example the names to a Dropdown-List. I just want to code the derived class without changing anything else in the project, recompile, bingo!

    If you have alternative solutions: tell em.

    Thanks

  • Steven Jeuris
    Steven Jeuris over 13 years
    +1: I believe that's pretty much the only solution.
  • trampi
    trampi over 13 years
    Thank you very much! My solution is based on your suggestions.
  • trampi
    trampi over 13 years
    Thanks for your answer, assembly.gettypes() was something i needed for the solution.
  • trampi
    trampi over 13 years
    Thanks, very interesting. Need to take a closer look on Activator.CreateInstance
  • user2341923
    user2341923 almost 10 years
    Can a type be not-abstract and non-class at the same time?
  • Admin
    Admin over 8 years
    This is absolutely insane! I had no idea you could do stuff like this with reflection.
  • Cesar
    Cesar over 7 years
    @user2341923 an enum?
  • mrexodia
    mrexodia over 7 years
    Use t.GetConstructor(Type.EmptyTypes) != null as an additional constraint to prevent trying to instantiate classes that don't have a parameterless constructor.
  • tobriand
    tobriand over 7 years
    What if the sub-class could be defined in a different assembly?
  • Brain2000
    Brain2000 almost 6 years
    @tobriand This will search all assemblies: AppDomain.CurrentDomain.GetAssemblies().SelectMany(s => s.GetTypes()).Where(....
  • tobriand
    tobriand almost 6 years
    I've used that a couple of times in the last few years... does sometimes catch me out though when there's a reference that's managed to creep through without some of its dependencies. But yes, it grabs subtypes :). Worth noting that GetAssemblies() get's the loaded assemblies, not the referenced ones, from memory. This can sometimes be a pain.
  • Michael
    Michael over 5 years
    How do I bookmark this!!!