2010-11-04 20 views
33

Powiedzmy mam następujące klasyWywołanie ogólne metody z dynamicznym typu

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

Teraz w niektórych kodu później chcę czytać w jakie zwierzę utworzyć.

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

Problem polega na tym, że ostatni wiersz jest nieprawidłowy. Czy istnieje jakiś elegancki sposób, aby to zrobić?

+2

Generics nie są tak naprawdę do zrobienia, powinieneś po prostu utworzyć listę zamiast tego i użyć Activator do utworzenia klas pochodnych. – Doggett

Odpowiedz

18

Niezupełnie. Zasadniczo musisz użyć odbicia. Generics są naprawdę ukierunkowane na pisanie na maszynie , a nie na typy znane tylko w czasie wykonywania.

Aby użyć odbicia, należy użyć Type.GetMethod, aby uzyskać definicję metody, a następnie wywołać MethodInfo.MakeGenericMethod(type), a następnie wywołać ją jak każdą inną metodę.

46

nie wiem o elegancki, ale sposób, aby to zrobić jest:

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

Chociaż nie będzie można go rzucić jako 'List ' lub 'List ' itp, chyba że znasz już typ podczas kompilacji, którego nie masz. Najlepsze, co możesz zrobić, to rzucić na "IList". – LukeH

+0

@LukeH, racja, dobra uwaga. –

+0

to jest takie brzydkie, ale jest to właściwa odpowiedź. – tofutim

1

Kluczem do tego są MakeGenericType() i MakeGenericMethod(). Po przejściu dynamicznego z typami, nie można naprawdę wrócić do pisania statycznego. Co możesz zrobić, to dynamicznie tworzyć listę, używając Activator.CreateInstance(typeof(List<>).MakeGenericType(type)), a następnie dynamicznie wywołując metodę ogólną, używając podobnych metod refleksyjnych.

3

Spróbuj tego:

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 
} 

Należy upewnić się, że dozwolone typy dla CreateAnimals dziedziczą Animal. Potem mam nadzieję, że nie będzie miał problemu z List<animalType> animals = creator.CreateAnimals<type>(5);

+0

To naprawdę nie pomaga, jeśli OP chce przeczytać, w którym typie zwierząt stworzyć z ciągu. –

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

W powyższej linii z Twojego przykład animalType i type prowadzone są zmienne razem nie typów, więc jest to oczywiście nonsens. Generycznej wersji ma sens tylko, jeśli wiesz typów w czasie kompilacji, np .:

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

gdzie trzeba by ograniczenie rodzajów odpowiednio. Jeśli typy nie są znane, musisz polegać całkowicie na odbiciu ...

Powiązane problemy