2012-05-22 9 views
6

Obecnie używam Generics do tworzenia dynamicznych metod, takich jak tworzenie obiektów i wypełnianie właściwości wartościami.Tworzenie zmiennych ogólnych z typu - Jak? Lub użyj Activator.CreateInstance() z właściwościami {} zamiast parametrów()?

Czy istnieje sposób na "dynamiczne" tworzenie generycznych bez znajomości typu? Na przykład:

List<String> = new List<String>() 

jest predefinied sposób, ale

List<(object.GetType())> = new List<(object.GetType()>() 

nie działa ... ale może?

To nie działa (Czy istnieje podobna podejście, które działa?)

public T CreateObject<T>(Hashtable values) 
    { 
     // If it has parameterless constructor (I check this beforehand) 
     T obj = (T)Activator.CreateInstance(typeof(T)); 

     foreach (System.Reflection.PropertyInfo p in typeof(T).GetProperties()) 
     { 
      // Specifically this doesn't work 
      var propertyValue = (p.PropertyType)values[p.Name]; 
      // Should work if T2 is generic 
      // var propertyValue = (T2)values[p.Name]; 

      obj.GetType().GetProperty(p.Name).SetValue(obj, propertyValue, null); 
     } 
    } 

Więc w skrócie: jak zrobić „typ” i utworzyć obiekt od tego bez użycia Generics? Dotychczas stosowałem tylko generyczne metody, ale czy można używać tych samych metod do zmiennych? Muszę zdefiniować rodzajowy (T) przed metodą, więc czy mogę zrobić to samo na zmiennych przed ich "utworzeniem"?

... lub jak użyć "Activator", aby utworzyć obiekt z właściwościami zamiast parametrów. Jak to zrobić tutaj:

// Z parametrów wartości

Test t = new Test("Argument1", Argument2); 

// o właściwościach

Test t = new Test { Argument1 = "Hello", Argument2 = 123 }; 

Odpowiedz

13

Można użyć MakeGenericType:

Type openListType = typeof(List<>); 
Type genericListType = openListType.MakeGenericType(obj.GetType()); 
object instance = Activator.CreateInstance(genericListType); 
+0

Nie chcę używać "List" w tym przypadku, powinien to być dowolny obiekt. "Typ openListType = typeof (nieznany typ);" – Deukalion

+0

Nie widzę, jak ta odpowiedź rozwiązuje OP "użyj Activator.CreateInstance() z właściwości {} zamiast parametrów()?" – Avishek

1

Podczas korzystania z obiektu inicjator, to tylko przy użyciu domyślnego konstruktora (bez parametrów), następnie ustawianie poszczególnych właściwości po skonstruowaniu obiektu.

Powyższy kod jest bliski - ale var nie będzie tutaj działał, ponieważ jest to po prostu propagacja typu kompilacji. Skoro już przy użyciu odbicia, można po prostu użyć System.Object:

object propertyValue = values[p.Name]; 

SetValue połączenie będzie działać dobrze z System.Object.

+0

Więc jak mogę używać Activator.CreateInstance z „Object inicjator "jako argument? Otrzymuję komunikat o błędzie "Brak definicji konstruktora bez parametrów dla tego obiektu". Typami właściwości, do których próbuję dodać wartości są: String, Double, enum, bool. Typ, którego nie powiedzie się, to "String". Nie ma konstruktora bez parametrów, więc nie mogę utworzyć łańcucha i dodać do niego wartości, ale jak to możliwe, ponieważ mogę zdefiniować: String str; lub String str = "To jest ciąg znaków"; – Deukalion

+0

@Deukalion Generowany typ nie ma konstruktora bez parametrów, więc nie można używać tej techniki z nim ... –

+0

Składnia 'String str =" Foo ";' jest funkcją języka C#, a nie Funkcja CLR. –

5

Można użyć metody MakeGenericType aby uzyskać ogólny typ dla konkretnego typu argumentu:

var myObjListType = typeof(List<>).MakeGenericType(myObject.GetType()); 
var myObj = Activator.CreateInstance(myObjListType); 
// MyObj will be an Object variable whose instance is a List<type of myObject> 
+0

Ale mówię, że obiekt, który tworzę, jest "String, boolean, int, float ..." niekoniecznie klasy. Jeśli muszę ustawić wartość przed ustawieniem właściwości obiektów na wartość. – Deukalion

+0

Dla typów wartości nie trzeba ustawiać wartości - mają one automatycznie poprawną wartość domyślną. Na przykład, pole typu 'bool' nie musi być zainicjalizowane na' false', ponieważ dzieje się to automatycznie. W przypadku łańcuchów zaczynają one od wartości null. Jeśli chcesz, aby miały inną wartość, np. "Fred", musisz ustawić ich wartość na "Fred". Nie 'Person.FirstName = new String (" Fred ");', widzisz? –

Powiązane problemy