2011-03-23 120 views
79

的所有继承类我有一个抽象类:获取一个抽象类

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() 
    { 
     ... 
    } 
} 

是否有可能做这样的事情? (伪代码:)

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

与像

CsvExporter 
XmlExporter 

输出?

这背后的想法是只要创建一个从AbstractDataExport得出这样我就可以通过全部实现自动循环和名称添加到例如下拉框中列出一个新的类。 我只想编写派生类而不更改项目中的任何其他内容,重新编译,宾果!

如果您有其他解决方案:告诉em。

感谢

回答

116

这是这样一个共同的问题,尤其是在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,以便可以对它们进行排序。
  • 您的子类必须具有相同的构造函数签名,否则会引发异常。这对我来说通常不是问题。
+1

一个类型可以同时不抽象和非类吗? – user2341923 2014-09-11 19:14:31

+1

这绝对是疯了!我不知道你可以用反射来做这样的事情。 – CanadaIT 2016-02-23 05:01:23

+0

@ user2341923一个枚举? – Cesar 2016-10-23 10:32:31

10

它可能不是优雅的方式,但你可以遍历所有类的组装和调用Type.IsSubclassOf(AbstractDataExport) 的每一个。

+1

+1:我相信这几乎是唯一的解决方案。 – 2011-03-23 21:20:50

+0

非常感谢!我的解决方案基于您的建议。 – trampi 2011-03-23 21:41:41

3

typeof(AbstractDataExport).Assembly告诉你,你的类型分布在(假设所有的都是一样的)组件。

assembly.GetTypes()为您提供所有类型在组装或assembly.GetExportedTypes()给你是公共类型。

遍历类型并使用type.IsAssignableFrom()可以指示是否派生类型。

+0

感谢您的回答,assembly.gettypes()是我需要的解决方案。 – trampi 2011-03-23 21:43:00

34

假设它们在同一程序都被定义,你可以这样做:

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

谢谢,非常有趣。需要仔细查看'Activator.CreateInstance' – trampi 2011-03-23 21:45:46

+3

使用't.GetConstructor(Type.EmptyTypes)!= null'作为附加约束来防止尝试实例化没有无参数构造函数的类。 – mrexodia 2016-11-02 19:02:38

0

好,反射在这里你的朋友。实施在此之前,你可能要考虑的是性能方面 - “反思总是昂贵的” :-)

+1

感谢您的回答!你能否提供更多有关执行速度缓慢的信息?有什么比较? :) – trampi 2011-03-23 21:54:02