2011-03-23 55 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