2010-11-04 34 views
33

一個通用的方法可以說我有以下類調用帶有動態類型

public class Animal { .... } 

public class Duck : Animal { ... } 

public class Cow : Animal { ... } 

public class Creator 
{ 
    public List<T> CreateAnimals<T>(int numAnimals) 
    { 
     Type type = typeof(T); 
     List<T> returnList = new List<T>(); 
     //Use reflection to populate list and return 
    } 
} 

現在一些代碼後,我想創造什麼樣的動物閱讀。

Creator creator = new Creator(); 
string animalType = //read from a file what animal (duck, cow) to create 
Type type = Type.GetType(animalType); 
List<animalType> animals = creator.CreateAnimals<type>(5); 

現在問題是最後一行是無效的。那麼有沒有一些優雅的方式來做到這一點?

+2

泛型不是真正的方式去這裏,你應該創建一個List 而不是使用Activator來創建派生類。 – Doggett 2010-11-04 22:24:49

回答

18

不是。基本上你需要使用反射。泛型實際上是針對靜態類型,而不是僅在執行時已知的類型。

要使用反射,您需要使用Type.GetMethod來獲取方法定義,然後調用MethodInfo.MakeGenericMethod(type),然後像調用其他方法一樣調用它。

46

我不知道優雅,但做到這一點的方法是:

typeof(Creator) 
    .GetMethod("CreateAnimals") 
    .MakeGenericMethod(type) 
    .Invoke(creator, new object[] { 5 }); 
+2

雖然你不能將它作爲'List '或者'List '等投入,除非你在編譯時已經知道這個類型,你不知道。你可以做的最好的就是投向「IList」。 – LukeH 2010-11-04 22:05:58

+0

@LukeH,對,好點。 – 2010-11-04 22:27:38

+0

這是如此醜陋,但它是正確的答案 – tofutim 2017-12-08 23:45:52

1

這個鍵是MakeGenericType()和MakeGenericMethod()。一旦你使用了這些類型,你就無法真正回到靜態類型。你可以做的是動態創建列表,使用Activator.CreateInstance(typeof(List<>).MakeGenericType(type)),然後使用類似的反射方法動態調用泛型方法。

3

試試這個:

public List<T> CreateAnimals<T>(int numAnimals) where T : Animal 
{ 
    Type type = typeof(T); 
    List<T> returnList = new List<T>(); 
    //Use reflection to populate list and return 
} 

應該確保允許的類型CreateAnimals從動物繼承。然後希望,這不會有List<animalType> animals = creator.CreateAnimals<type>(5);

+0

如果OP想要讀取從字符串創建哪種動物類型,這並沒有什麼幫助。 – 2010-11-04 22:05:05

0
List<animalType> animals = 
creator.CreateAnimals<type>(5); 

在從例如上面的行問題,animalTypetype的運行時間變量,而不是類型,所以這當然是無稽之談。如果您知道編譯時的類型,通用版本纔有意義,例如:

List<Animal> animals = 
    creator.CreateAnimals<Cow>(5); 

其中您必須相應地約束類型。如果類型不知道,你必須完全依靠反射...