Generating a list of child classes with reflection in .NET 3.5
Asked Answered
B

4

6

At runtime, I would like to specify a parent class, and then the program would generate a list of all children classes (of however many generations). For example, if I had Entity as a parent, and Item:Entity and Actor:Entity, there would be two strings, "Actor" and "Item".

I see that System.Reflection.TypeInfo is exactly what I am looking for. However, it appears this is exclusive to .NET 4.5, and my environment is unfortunately stuck at 3.5.

Is there an alternative way to do this in .NET 3.5, or should I consider an upgrade?

Boathouse answered 15/12, 2012 at 22:19 Comment(0)
F
10
var pType = typeof(Entity);
IEnumerable<string> children = Enumerable.Range(1, iterations)
   .SelectMany(i => Assembly.GetExecutingAssembly().GetTypes()
                    .Where(t => t.IsClass && t != pType
                            && pType.IsAssignableFrom(t))
                    .Select(t => t.Name));

Demo

Frontolysis answered 15/12, 2012 at 22:36 Comment(1)
Be wary to not put it the other way around when copying it without paying too much attention. t.IsAssignableFrom(pType) will return false.Siebert
D
4

One possible way would utilize the Type.IsAssignableFrom method. You would loop over all types, and select those for which it is true.

Basically, it would be something like

Type parent = Type.GetType("Entity");
Type[] types = Assembly.GetExecutingAssembly().GetTypes(); // Maybe select some other assembly here, depending on what you need
Type[] inheritingTypes = types.Where(t => parent.IsAssignableFrom(t));

I don't have a compiler available at this time, so I can't verify it, but it should be mostly correct

Dialyser answered 15/12, 2012 at 22:24 Comment(3)
Oh perfect, I was going to ask the best way to generate a list in the first place, and that's more or less the method that was recommended from a quick search of SO.Boathouse
I'll point out that Assembly.GetExecutingAssembly() won't work across assembly boundaries. If you want to work across assemblies, you can use AppDomain.CurrentDomain.GetAssemblies().Indenture
@Danjen: Note that this will also return interfaces and the parent class itself. If this is not wanted, you'll need to filter a bit. Also, as Kendall notes, you need to think a bit about what assembly/assemblies you want to search. But this should get you started.Dialyser
D
1

You can use the following code:

var parrents = Assembly.GetExecutingAssembly().GetTypes().Where(a => typeof(Person).IsAssignableFrom(a)).ToList();
Dissentient answered 17/10, 2021 at 17:9 Comment(1)
That works perfect, but it should be var children instead of var parrentsKnotgrass
C
0

This is what I use to find all children of some class (can be also abstract class) in selected assembly:

public class InheritedFinder
{
    public static Type[] FindInheritedTypes(
        Type parentType, Assembly assembly)
    {
        Type[] allTypes = assembly.GetTypes();
        ArrayList avTypesAL = new ArrayList();

        return allTypes.Where(
            t => parentType.IsAssignableFrom(t) && t != parentType).ToArray();
    }
}

Simply call by

var availableTypes = InheritedFinder.FindInheritedTypes(
        typeof(YourBaseClass),
        System.Reflection.Assembly.GetExecutingAssembly());

This will give you list of available children of YourBaseClass. Nice thing about it - it'll find also children of children, so you can use multi-level abstract classes. If you need to create instances of every child, easy:

var availableTypes= InheritedFinder.FindInheritedTypes(
    typeof(Shape), System.Reflection.Assembly.GetExecutingAssembly());
foreach (var t in availableTypes)
{
    try
    {
        YourBaseClass nInstance = (YourBaseClass)Activator.CreateInstance(t);
        //nInstance is now real instance of some children
    }
    catch (Exception e)
    {
        //recommended to keep here - it'll catch exception in case some class is abstract (=can't create its instance)
    }
}
Culinarian answered 30/3, 2020 at 14:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.