Get all inherited classes of an abstract class [duplicate]
I have an abstract class:
abstract class AbstractDataExport
{
public string name;
public abstract bool ExportData();
}
I hav开发者_StackOverflow社区e 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
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.
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));
It may not be the elegant way but you can iterate all classes in the assembly and invoke Type.IsSubclassOf(AbstractDataExport)
for each one.
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.
精彩评论