获取抽象类的所有继承类

我有一门抽象课:

abstract class AbstractDataExport
{
public string name;
public abstract bool ExportData();
}

我有一些从 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()
{
...
}
}

有可能做这样的事情吗? (Pseudocode:)

foreach (Implementation imp in Reflection.GetInheritedClasses(AbstractDataExport)
{
AbstractDataExport derivedClass = Implementation.CallConstructor();
Console.WriteLine(derivedClass.name)
}

输出类似

CsvExporter
XmlExporter

其背后的想法是创建一个新的类,它是从 AbstractDataExport 派生出来的,这样我就可以自动迭代所有的实现,并将名称添加到下拉列表中。 我只是想在不改变项目中任何其他内容的情况下编写派生类,重新编译,宾果!

如果你有其他的解决办法: 告诉他们。

谢谢

141051 次浏览

这可能不是一种优雅的方式,但是您可以迭代程序集中的所有类并调用 Type.IsSubclassOf(AbstractDataExport) 每一个。

typeof(AbstractDataExport).Assembly告诉您类型所在的程序集(假设所有类型都位于相同的程序集中)。

assembly.GetTypes()为您提供该程序集中的所有类型,或者 assembly.GetExportedTypes()为您提供公共类型。

通过对类型进行迭代并使用 type.IsAssignableFrom()可以判断该类型是否派生。

假设它们都在同一个程序集中定义,您可以:

IEnumerable<AbstractDataExport> exporters = typeof(AbstractDataExport)
.Assembly.GetTypes()
.Where(t => t.IsSubclassOf(typeof(AbstractDataExport)) && !t.IsAbstract)
.Select(t => (AbstractDataExport)Activator.CreateInstance(t));

这是一个非常常见的问题,特别是在 GUI 应用程序中,我很惊讶没有一个 BCL 类可以开箱即用。我是这么做的。

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;
}
}

一些注意事项:

  • 不要担心这个操作的“成本”——你只会做一次(希望如此) ,即使那样也不会像你想象的那么慢。
  • 您需要使用 Assembly.GetAssembly(typeof(T)),因为您的基类可能位于不同的程序集中。
  • 您需要使用标准 type.IsClass!type.IsAbstract,因为如果您尝试实例化接口或抽象类,它将抛出异常。
  • 我喜欢强制枚举类实现 IComparable,这样就可以对它们进行排序。
  • 您的子类必须具有相同的构造函数签名,否则它将抛出异常。