2012-12-19 47 views
21

獲取類我有一個抽象類,有幾個派生類通過字符串值

public abstract class MyObject 
{ 
    public string name { get; set; } 
    public bool IsObject(string pattern); 
    ... 
} 

public class MyObjectA : MyObject 
{ 
    public string name { get { return "MyObjectA"; } set; } 
    public bool IsObject(string pattern) { ... } 
    ... 
} 

public class MyObjectB: MyObject 
{ 
    public string name { get { return "MyObjectB"; } set; } 
    public bool IsObject(string pattern) { ... } 
    ... 
} 

現在我想有一個函數,它返回我的基於字符串的特定類(MyObjectA/MyObectB)。問題是,我有很多if/else-clause來得到它:

public MyObject Create(string pattern) 
{ 
    MyObjectA obj = new MyObjectA(); 
    if(obj.IsObject(pattern) 
    { 
     return obj; 
    } 
    else 
    { 
     MyObjectB objb = new MyObjectB(); 
     if(objb.IsObject(pattern); 
      return objb; 
     else 
      ... 
    } 
} 

這看起來很糟糕。什麼是更好的方法來做到這一點?

回答

28

是的,使用反射。

您可以使用Type.GetType得到Type的實例,通過串類,然後使用Activator.CreateInstance,這樣的實例是:

public MyObject Create(string pattern) 
{ 
    Type t = Type.GetType(pattern); 
    if (t == null) { 
     throw new Exception("Type " + pattern + " not found."); 
    } 
    return Activator.CreateInstance(t); 
} 

你可以使用Activator.CreateInstance(string, string)超載也有,但是這不會直接返回所需的Type的新實例。

5

正如Rudi Visser所說,您應該使用reflection

同樣爲了得到你的類名,你不應該對它進行硬編碼。 如果whant使用您的name屬性只寫

public abstract class MyObject 
{ 
    public string name 
    { 
     get 
     { 
      return this.GetType().Name; 
     } 
    } 
    public bool IsObject(string pattern); 
    ... 
} 

,如果你不上課的,代表它的名字,只是一些字符串,比你可以檢查得出的所有類別的MyObject

public MyObject Create(string pattern) 
{ 
    Type[] types = Assembly.GetExecutingAssembly().GetTypes(); 
    foreach (Type type in types.Where(t => t.IsSubclassOf(typeof(MyObject)))) 
    { 
     MyObject obj = (MyObject)Activator.CreateInstance(type); 
     if (obj.name == pattern) 
     { 
      return obj; 
     } 
    } 
    throw new Exception("Type " + pattern + " not found."); 
} 
+0

+1良好的通話。顯式刪除'set'也是很好的。 –

+0

這只是一個例子。名稱字符串不是確切的類名稱,但我可以將其轉換爲它。 – Link

0

它可以使用反射像這樣做...

public object getInstance(string assemblyName, string className, object[] constructorParameters) 
    { 
     System.Reflection.Assembly asm = System.Reflection.Assembly.Load(assemblyName); 
     return asm.CreateInstance(className, false, System.Reflection.BindingFlags.CreateInstance, null, constructorParameters, null, null); 
    } 

的AssemblyName - 完整路徑+集名稱

className - 合格的班級名稱

1

對於您陳述的問題有很多很好的答案。然而,我會建議你爲這種類型的需求使用工廠模式。

您的'工廠'可能就像爲您的基類添加靜態GetNewMyObject(string pattern)方法一樣簡單,以及protected static Dictionary<string, Type>。然後你的派生類可以簡單地將它們的模式+類型添加到工廠(在靜態構造函數中),允許將新的派生類添加到工廠而不修改基類。

這樣,你的「模式」字符沒有相匹配的類型名稱,你也並不需要做任何邏輯模式匹配,你可以這樣寫:

public static MyObject GetNewMyObject(string pattern) 
{ 
    return (MyObject)Activator.CreateInstance(StaticTypeDictionary[pattern]); 
}