This question already has an answer here:
-
How do I use reflection to call a generic method?
7 answers
I need to create at runtime instances of a class that uses generics, like class<T>
, without knowing previously the type T they will have, I would like to do something like that:
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;
}
...but I can't. I think it is not possible to write in C# inside the generic brackets a type variable. Is there another way to do it?
You can't do it like that - the point of generics is mostly compile-time type-safety - but you can do it with reflection:
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;
}
Depending on how often you're calling this method then using Activator.CreateInstance could be slow. Another option is to do something like this:
private Dictionary> delegates = new Dictionary>();
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>();
}
On the first hit it'll create a delegate to the generic method that creates the list and then puts that in a dictionary. On each subsequent hit you'll just call the delegate for that type.
Hope this helps!