Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dynamic type with lists in c#

Tags:

c#

types

dynamic

I have a little problem for you guys.

I would like to do this:

Type[] classes = new Type[]{ Class1, Class2 };

foreach(Type t in classes){   
  List<t> list = new List<t>(); 
}

Is there some way to do this?

like image 821
Stian Standahl Avatar asked May 25 '12 12:05

Stian Standahl


3 Answers

You cannot cast to a generic type at runtime, because the type in the generic needs to be resolved at compile time.

You can create a generic type in a dynamic manner using reflection, but unless you hard-code the cast, all you get in return is an object.

I cannot really tell what it is you want, I have to agree with a comment this is an XY problem. I would be inclined to make the presumptuous statement that there is a design issue somewhere that this is trying to solve, instead of addressing the design issue directly, or asking the question of what you are trying to achieve directly.


You can use the following code to create the type, then the dynamic type can be used to duck type the various members of List<T> without knowing/caring that it is a list or what T is:

using System;
using System.Collections.Generic;

namespace ConsoleApplication61
{
    class Program
    {
        static void Main(string[] args)
        {
            dynamic o = CreateGeneric(typeof(List<>), typeof(int));
            o.Add(1);
            Console.WriteLine(o[0]);
            Console.Read();
        }

        public static object CreateGeneric(Type generic, Type innerType, params object[] args)
        {
            System.Type specificType = generic.MakeGenericType(new System.Type[] { innerType });
            return Activator.CreateInstance(specificType, args);
        }
    }
}

The above sample duck types the Add method and the Indexer. The DLR does the type handling and the duck typing at runtime - knowing that 1 is an int, for example.

Just to clarify, I likely wouldn't use such code in production (unless you requirements are very specific to need this) and any issues with type-mismatching will occur at run time; so you either need to type very accurately (limited IntelliSense) or have good error handling.

Thanks to this blog post for the CreateGeneric method.

This assumes .NET 4 with the new CLR. As @MartinLiversage has also pointed out, this particular sample assumes that you are utilising the list in a sort-of-strongly-typed manner. In my example I am passing an int to a List<int> hidden in a dynamic.


We have been on .NET 4 almost since it was released. We have a large application with an even larger code base. dynamic isn't used once in the application, and only a few times in the test code base. That isn't to say "don't use it", it's to say "most of the time, you don't need it".

like image 131
Adam Houldsworth Avatar answered Oct 12 '22 14:10

Adam Houldsworth


You can do it like this:

foreach(Type t in classes)
{
   var listType = typeof(List<>).MakeGenericType(t);
   var instance = Activator.CreateInstance(listType);
}
like image 33
Erwin Avatar answered Oct 12 '22 15:10

Erwin


This is possible with the Type.MakeGenericType Method

Here's a nifty method I found that should work for ya: CodeRef

public static object CreateGeneric(Type generic, Type innerType, params object[] args)
{
    System.Type specificType = generic.MakeGenericType(new System.Type[] { innerType });
    return Activator.CreateInstance(specificType, args);
}

And use it like so:

var o = CreateGeneric(typeof(List<>), t);

Unfortunately, to add items you'll have to do it like so (where item is the item you're adding).

MethodInfo addMethod = o.GetType().GetMethod("Add");
addMethod.Invoke(o, new object[] { item.ToType(t) });

Or use the Generic type as mentioned in another answer.

like image 21
Chris Gessler Avatar answered Oct 12 '22 13:10

Chris Gessler