Get All Inherited Classes of an Abstract Class

Get all inherited classes of an abstract class

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.

Get all inherited classes of a generic abstract class

Actually getting the instance to invoke Search() (and only search) can be done by breaking up the abstract class:

public abstract class AbstractRequest
{
public abstract void Search();
}

public abstract class AbstractRequest<TResponseData> : AbstractRequest
where TResponseData : IResponseData
{
public abstract GoodData BindData(TResponseData data);
}

And then you can use your original (non-generic) code:

var instances = from t in Assembly.GetExecutingAssembly().GetTypes()
where t.IsClass &&
typeof(AbstractRequest).IsAssignableFrom(t) &&
t.GetConstructor(Type.EmptyTypes) != null
select Activator.CreateInstance(t) as AbstractRequest;

(Old, busted solution)

I think that I would do something like this (untested):

var abstractRequestTypes =
(from t in Assembly.GetExecutingAssembly().GetTypes()
where t.IsClass &&
typeof(IResponseData).IsAssignableFrom(t)
select typeof(AbstractRequest<>).MakeGenericType(t)).ToList();

var instanceTypes = from t in Assembly.GetExecutingAssembly().GetTypes()
where t.IsClass &&
abstractRequestTypes.Any(dt => dt.IsAssignableFrom(t));

This should cover anything in the inheritance hierarchy, taking advantage of the type constraint on AbstractRequest.

How can I get all the inherited classes of a base class?

This is not fast, but as long as Foo is a concrete type (not an interface), then it should work. Foo itself is not returned by this code.

AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(assembly => assembly.GetTypes())
.Where(type => type.IsSubclassOf(typeof(Foo)));

Get all classes that implement a certain abstract class

using System.Reflection;
using Microsoft.Extensions.DependencyModel;
var asmNames = DependencyContext.Default.GetDefaultAssemblyNames();
var type = typeof(BaseViewComponent);

var allTypes = asmNames.Select(Assembly.Load)
.SelectMany(t => t.GetTypes())
.Where(p => p.GetTypeInfo().IsSubclassOf(type));

Get all sub classes of generic abstract base class

You can do the following (C# 7 syntax follows):

public static IEnumerable<Type> GetAllDescendantsOf(
this Assembly assembly,
Type genericTypeDefinition)
{
IEnumerable<Type> GetAllAscendants(Type t)
{
var current = t;

while (current.BaseType != typeof(object))
{
yield return current.BaseType;
current = current.BaseType;
}
}

if (assembly == null)
throw new ArgumentNullException(nameof(assembly));

if (genericTypeDefinition == null)
throw new ArgumentNullException(nameof(genericTypeDefinition));

if (!genericTypeDefinition.IsGenericTypeDefinition)
throw new ArgumentException(
"Specified type is not a valid generic type definition.",
nameof(genericTypeDefinition));

return assembly.GetTypes()
.Where(t => GetAllAscendants(t).Any(d =>
d.IsGenericType &&
d.GetGenericTypeDefinition()
.Equals(genericTypeDefinition)));
}

This will return any type that inherits directly or indirectly from the specified generic type definition.

In the following scenario:

class Base { }
class Base<T>: Base { }
class Foo : Base<int> { }
class Bar : Base<string> { }
class Frob : Bar { }
class FooBar: Base { };

var genericTypeDefinition = typeof(Base<>);
var types = Assembly.GetExecutingAssembly()
.GetAllDescendantsOf(genericTypeDefinition)));

GetAllDescendantsOf will output Foo, Bar and Frob.

In metro, get all inherited classes of an (abstract) class?

This should work (based on the code from here):

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

Basically TypeInfo is now the main class for doing any reflection operations and you can get it by calling GetTypeInfo() on the Type.

How can I know the classes that extend my base class at runtime?

Use reflection to get the loaded assemblies and then enumerate through all types that are a subclass of your base class.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
var types = new List<Type>();

foreach (var assembly in assemblies)
types.AddRange(assembly.GetTypes().Where(x => x.IsSubclassOf(typeof(Animal))));

foreach (var item in types)
Console.WriteLine(item.Name);
}
}

class Animal { }

enum AllAnimals { Cat, Dog, Pig };
class Cat : Animal { }
class Dog : Animal { }
class Pig : Animal { }
}

How access properties of Inherited classes from abstract class

If you know what concrete type you'll have, you can always cast your object:

var concreteObject = myObj as classOne;

Or, if you don't know what object type you'll have, you can test for it and then cast:

if (myObj is classOne) {
// Cast to classOne and use
} else if (myObj is classTwo) {
// Cast to classTwo and use
}

Hope this helps answer your question!

Ninject: GetAll instances that inherit from the same abstract class

instead of creating two bindings, the second one with a "redirect" to the first, what you can also do is:

_kernel.Bind<MyAbstractClass, MyDerivedClass1>()
.To<MyDerivedClass1>().InSingletonScope();
_kernel.Bind<MyAbstractClass, MyDerivedClass2>()
.To<MyDerivedClass1>().InSingletonScope();

This expresses the intention more clearly.



Related Topics



Leave a reply



Submit