Using reflection, is it possible to discover all types that derive from a given type?
Presumably the scope would be limited to within a single assembly.
Using reflection, is it possible to discover all types that derive from a given type?
Presumably the scope would be limited to within a single assembly.
pretty much the same as Darin's but here you go..
public static List<Type> FindAllDerivedTypes<T>()
{
return FindAllDerivedTypes<T>(Assembly.GetAssembly(typeof(T)));
}
public static List<Type> FindAllDerivedTypes<T>(Assembly assembly)
{
var baseType = typeof(T);
return assembly
.GetTypes()
.Where(t =>
t != baseType &&
baseType.IsAssignableFrom(t)
).ToList();
}
used like:
var output = FindAllDerivedTypes<System.IO.Stream>();
foreach (var type in output)
{
Console.WriteLine(type.Name);
}
outputs:
NullStream
SyncStream
__ConsoleStream
BufferedStream
FileStream
MemoryStream
UnmanagedMemoryStream
PinnedBufferMemoryStream
UnmanagedMemoryStreamWrapper
IsolatedStorageFileStream
CryptoStream
TailStream
var derivedTypes = from t in Assembly.GetExecutingAssembly().GetTypes()
where t.IsSubclassOf(typeof(A))
select t;
var types = Assembly
.GetExecutingAssembly()
.GetTypes()
.Where(t => typeof(SomeBaseType).IsAssignableFrom(t) &&
t != typeof(SomeBaseType))
.ToArray();
I rewrote @Hath's excellent answer as an extension method:
public static class TypeExtensions
{
public static List<Type> GetAllDerivedTypes(this Type type)
{
return Assembly.GetAssembly(type).GetAllDerivedTypes(type);
}
public static List<Type> GetAllDerivedTypes(this Assembly assembly, Type type)
{
return assembly
.GetTypes()
.Where(t => t != type && type.IsAssignableFrom(t))
.ToList();
}
}
Usage:
var listOfDerived = typeof(MyClass).GetAllDerivedTypes();
I know the OP specified within a single assembly, but since this question is one of the top results when trying to find how to do this I am giving an example of how to do this with all assemblies that derive from the assembly containing the given type.
/// <summary>
/// Gets all types derived from the given <paramref name="type"/>
/// <para>By default checks the assembly of the given type and all dependent assemblies.</para>
/// </summary>
/// <param name="type"></param>
/// <param name="allAssemblies">If false only the assembly containing the type will be checked.</param>
/// <returns></returns>
public static IEnumerable<Type> GetAllDerivedTypes(this Type type, bool allAssemblies = true)
{
List<Type> derivedTypes = type.GetAllDerivedTypes(Assembly.GetAssembly(type)!).AsList();
if (allAssemblies)
{
IEnumerable<Assembly> dependentAssemblies = GetDependentAssemblies(Assembly.GetAssembly(type)!);
derivedTypes.AddRange(dependentAssemblies.SelectMany(a => GetAllDerivedTypes(type, a)));
}
return derivedTypes;
}
private static IEnumerable<Assembly> GetDependentAssemblies(Assembly analyzedAssembly)
{
return AppDomain.CurrentDomain.GetAssemblies()
.Where(a => a.GetReferencedAssemblies()
.Select(assemblyName => assemblyName.FullName)
.Contains(analyzedAssembly.FullName));
}
private static IEnumerable<Type> GetAllDerivedTypes(this Type baseType, Assembly assembly)
{
TypeInfo baseTypeInfo = baseType.GetTypeInfo();
return assembly.DefinedTypes.Where(type =>
{
if (baseTypeInfo.IsClass)
{
return type.IsSubclassOf(baseType);
}
return baseTypeInfo.IsInterface && type.ImplementedInterfaces.Contains(baseTypeInfo.AsType());
}).Select(type => type.AsType());
}