tags:

views:

2143

answers:

8

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();
A: 

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>();
}
Nathan
That relies on the compiler being able to infer the type - which means it has to know the type at compile-time.
Jon Skeet
A: 

Pretty sure you can do that, they don't have to be fixed at compile time like templates in c++.

An example that is similar here: http://geekswithblogs.net/marcel/archive/2007/03/24/109722.aspx

seanb
A: 

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>();
abelenky
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.
Jon Skeet
A: 

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();
   }
}
KevinT
A: 

See the answer from the similar question "Dynamically Create a Generic Type for Template". The only difference is that they are generating the type from the command line, the rest you should be able to adapt to your needs.

As an aside, you cannot call typeof on an instance - to get the type of an instance (for example "i" call GetType():

Type intType = i.GetType();
Brian B.
+12  A: 

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.

Jon Skeet
You could return a non-generic IList (which is supported by List<>), then the returned list would be of use.
configurator
In which case it would be simpler to use an ArrayList to start with.
Jon Skeet
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?
Sekhat
Yes, it would throw an exception.
Jon Skeet
A: 

While your example used a list, there is another way that you can create a generic (Though it doesn't work well with a list. You can't call any of it's methods easily because of the generic parameters in all it's calls.)

I have used this method in the past quite often when I create a non-generic base class and have a generic child class. If you do this, you can recast the object as it's non-generic base class and use it's methods like normal.

object SomeGeneric = 
        Activator.CreateInstance(typeof(SomeGenericClass<>).MakeGenericType(someUnknownObject.GetType()));
Xenophile
A: 

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