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
Running Scripts in HTMLagilitypack
Best and Shortest Way to Evaluate Mathematical Expressions
How to Get a Path to the Desktop for Current User in C#
Access to Modified Closure (2)
How to Render a Formula in Wpf or Winforms
Implicit Operator Using Interfaces
Mvc3 Razor Dropdownlistfor Enums
C# Winforms Combobox Dynamic Autocomplete
What Is the Async/Await Equivalent of a Threadpool Server
How to Configure the Web.Config to Allow Requests of Any Length
Opening New Window in Mvvm Wpf
Value of Type 'T' Cannot Be Converted To
Does It Make Sense to Use "As" Instead of a Cast Even If There Is No Null Check
Swap Two Variables Without Using a Temporary Variable
Tuples( or Arrays ) as Dictionary Keys in C#