32

Is it possible to declare an instance of a generic without knowing the type at design-time?

Example:

Int i = 1;
List<typeof(i)> list = new List<typeof(i)>();

where the type of i could be anything, instead of having to do:

List<int> list = new List<int();
0

5 Answers 5

47

If you don't know the type at compile-time, but you want the actual type (i.e. not List<object>) and you're not in a generic method/type with the appropriate type parameter, then you have to use reflection.

To make the reflection simpler, I've sometimes introduced a new generic type or method in my own code, so I can call that by reflection but then just use normal generics after that. For example:

object x = GetObjectFromSomewhere();
// I want to create a List<?> containing the existing
// object, but strongly typed to the "right" type depending
// on the type of the value of x
MethodInfo method = GetType().GetMethod("BuildListHelper");
method = method.MakeGenericMethod(new Type[] { x.GetType() });
object list = method.Invoke(this, new object[] { x });

// Later

public IList<T> BuildListHelper<T>(T item)
{
    List<T> list = new List<T>();
    list.Add(item);
    return list;
}

Of course, you can't do an awful lot with the list afterwards if you don't know the type... that's why this kind of thing often falls down. Not always though - I've used something like the above on a few occasions, where the type system just doesn't quite let me express everything I need to statically.

EDIT: Note that although I'm calling Type.GetMethod in the code above, if you were going to execute it a lot you'd probably want to just call it once - after all, the method isn't going to change. You may be able to make it static (you could in the case above) and you probably want to make it private too. I left it as a public instance method for the simplicity of the GetMethod call in sample code - you'd need to specify the appropriate binding flags otherwise.

Sign up to request clarification or add additional context in comments.

7 Comments

You could return a non-generic IList (which is supported by List<>), then the returned list would be of use.
In which case it would be simpler to use an ArrayList to start with.
ah but adding the wrong type to the collection when it's cast as IList will still through an exception about it being the wrong type will it not?
Yes, it would throw an exception.
12 years later and this answer helps me again! Thanks @JonSkeet
|
2

If you don't know the type at design-time, I'd say you have a list of OBJECTS (the base class for all other types).

List<object> list = new List<object>();

1 Comment

No, you can still create a list of the appropriate type and pass it to something which may be able to do a cast to the right type and work with it in a statically typed way thereafter. Just because one piece of code doesn't know the type doesn't mean that nothing knows the type.
1

I think the best you are going to be able to do is something like this:

static void Main(string[] args)
{
    int i = 1;
    var thelist = CreateList(i);
}

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

1 Comment

That relies on the compiler being able to infer the type - which means it has to know the type at compile-time.
1

You can also use Activator.CreateInstance. Example code snippet:

public class BaseRepository<T> where T : DataContext
{
   protected T _dc;

   public BaseRepository(string connectionString)
   {
      _dc = (T) Activator.CreateInstance(typeof(T), connectionString);
   }

   public void SubmitChanges()
   {
      _dc.SubmitChanges();
   }
}

Comments

0

If you still want to type .Add(), .Remove(), do foreach etc. you can treat the List as a regular "old" System.Collections.IList, since this interface is luckily implemented by List<T>.

And since all other posted answers to this question shows pretty much every other possible way to create an instance of a List<T> dynamically, i will show one last way to do it. I personally use this method when creating generic instances, when i don't really know nothing about the type at compile time, and the type must be passed as a string, perhaps coming from the application configuration file. In this example, T is System.String for simplicity but it could be anything:

Type T = typeof ( string ); // replace with actual T
string typeName = string.Format (
  "System.Collections.Generic.List`1[[{0}]], mscorlib", T.AssemblyQualifiedName );

IList list = Activator.CreateInstance ( Type.GetType ( typeName ) )
  as IList;

System.Diagnostics.Debug.Assert ( list != null ); //

list.Add ( "string 1" ); // new T
list.Add ( "string 2" ); // new T
foreach ( object item in list )
{
  Console.WriteLine ( "item: {0}", item );
}

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.