2008-10-24 8 views
9

trzeba utworzyć w przypadkach runtime klasy, który używa rodzajowych, jak class<T>, nie znając wcześniej typ T będą mieli, chciałbym zrobić coś takiego:Czy dynamiczne używanie Generics jest niemożliwe?

public Dictionary<Type, object> GenerateLists(List<Type> types) 
{ 
    Dictionary<Type, object> lists = new Dictionary<Type, object>(); 

    foreach (Type type in types) 
    { 
     lists.Add(type, new List<type>()); /* this new List<type>() doesn't work */ 
    } 

    return lists; 
} 

... ale żargon. Myślę, że nie można pisać w języku C# w nawiasach ogólnych zmiennej typu. Czy jest inny sposób na zrobienie tego?

+0

Czy możesz podać powód, dla którego chcesz utworzyć bezpieczny obiekt ogólny w czasie wykonywania? –

+0

Zrobiłem to kilka razy, szczególnie podczas przenoszenia buforów protokołów. –

+0

Robię adapter do ram wytrwałości tutaj w mojej pracy, a klasy potrzebują tych informacji do wykonywania swojej pracy. –

Odpowiedz

17

Nie można zrobić to tak - punkt rodzajowych jest głównie kompilacji typu bezpieczeństwo - ale można zrobić to z refleksji:

public Dictionary<Type, object> GenerateLists(List<Type> types) 
{ 
    Dictionary<Type, object> lists = new Dictionary<Type, object>(); 

    foreach (Type type in types) 
    { 
     Type genericList = typeof(List<>).MakeGenericType(type); 
     lists.Add(type, Activator.CreateInstance(genericList)); 
    } 

    return lists; 
} 
+0

dzięki znowu Jon. Czy CreateInstance wymaga pustego konstruktora? Nie mam go, właściwie muszę wprowadzić parametr do niego. –

+0

Wymaga to konstruktora. Jeśli nie chcesz używać konstruktora, możesz użyć FormatterServices.GetUninitializedObject() w zestawie System.Runtime.Serialization. –

+1

@Victor: Istnieją przeciążenia Activator.CreateInstance, które pobierają parametry lub można użyć Type.GetConstructor, a następnie wywołać to. Zasadniczo istnieje wiele sposobów przechodzenia od typu do instancji typu - wybierz jeden :) –

4

W zależności od tego, jak często jesteś wywołanie tej metody przy użyciu Activator.CreateInstance może być wolne. Inną opcją jest zrobienie czegoś takiego:

prywatny słownik> delegaci = nowy słownik>();

public Dictionary<Type, object> GenerateLists(List<Type> types) 
    { 
     Dictionary<Type, object> lists = new Dictionary<Type, object>(); 

     foreach (Type type in types) 
     { 
      if (!delegates.ContainsKey(type)) 
       delegates.Add(type, CreateListDelegate(type)); 
      lists.Add(type, delegates[type]()); 
     } 

     return lists; 
    } 

    private Func<object> CreateListDelegate(Type type) 
    { 
     MethodInfo createListMethod = GetType().GetMethod("CreateList"); 
     MethodInfo genericCreateListMethod = createListMethod.MakeGenericMethod(type); 
     return Delegate.CreateDelegate(typeof(Func<object>), this, genericCreateListMethod) as Func<object>; 
    } 

    public object CreateList<T>() 
    { 
     return new List<T>(); 
    } 

Przy pierwszym trafieniu utworzy delegata do ogólnej metody, która tworzy listę, a następnie umieszcza ją w słowniku. Przy każdym kolejnym trafieniu po prostu zadzwonisz do delegata tego typu.

Mam nadzieję, że to pomoże!

+0

Dzięki jonni, tę metodę nazywam tylko raz, w przeciwnym razie zachowanie delegata byłoby dobrym rozwiązaniem. –

Powiązane problemy