C# Instantiate Generic List from Reflected Type

C# instantiate generic List from reflected Type

Try this:

void foobar(Type t)
{
var listType = typeof(List<>);
var constructedListType = listType.MakeGenericType(t);

var instance = Activator.CreateInstance(constructedListType);
}

Now what to do with instance? Since you don't know the type of your list's contents, probably the best thing you could do would be to cast instance as an IList so that you could have something other than just an object:

// Now you have a list - it isn't strongly typed but at least you
// can work with it and use it to some degree.
var instance = (IList)Activator.CreateInstance(constructedListType);

Create generic ListT with reflection

Assuming you know the property name, and you know it is an IEnumerable<T> then this function will set it to a list of corresponding type:

public void AssignListProperty(Object obj, String propName)
{
var prop = obj.GetType().GetProperty(propName);
var listType = typeof(List<>);
var genericArgs = prop.PropertyType.GetGenericArguments();
var concreteType = listType.MakeGenericType(genericArgs);
var newList = Activator.CreateInstance(concreteType);
prop.SetValue(obj, newList);
}

Please note this method does no type checking, or error handling. I leave that as an exercise to the user.

Using Reflection.Emit to instantiate Generic Type with Generic Parameters

Yeah, there's definitely a trick to this. Indeed you cannot call any methods on the TypeBuilderInstantiation. Instead, TypeBuilder will let you get constructors for dependent types.

The GetConstructor method provides a way to get a ConstructorInfo object that represents a constructor of a constructed generic type whose generic type definition is represented by a TypeBuilder object.

https://msdn.microsoft.com/en-us/library/ms145822(v=vs.110).aspx

You first need the generic ConstructorInfo, gotten from typeof(List<>) in the usual way...

var listDefaultConstructor = listType.GetConstructor(new Type[0]);

and then instantiate it to your particular generic implementation:

var c = TypeBuilder.GetConstructor(list_of_T, listDefaultConstructor);

Whenever you would like to call a method on an instance of Type that represents an unconstructed/dependent type, instead look for a method with the same name in the Reflection.Emit hierarchy.


Among other things, this design pattern of passing in the generic version of the MethodInfo allows you to distinguish between calls to overloaded Class<T=int>.Foo(T) and Class<T=int>.Foo(int).

passing generic list of reflected type to method in reflected type

What I tried so far:

  1. Passing a List containing stStruct items.

Without code thats hard to say what was wrong.


  1. Creating a struct that has the same definition as stStruct (cstStruct) in my code, then passing a List to the processItems method. (cannot convert list of x to list of y).

Well thats how typesafe languages work, its a different type.

The key to solve this problem is the Type.MakeGenericType method to create a generic type with a type parameter unknown at compile time. Keep in mind that the Assembly.GetType() method requires the type name inclusive the namespace. You can inline a few of these temp variables, i created them just to be a bit more clear about the general reflection process.

var businessTypeInstance = ...;
var processItemsMethod = businessTypeInstance.GetType().GetMethod("processItems");
var stStructType = businessTypeInstance.GetType().Assembly.GetType("stStruct");
var openListType = typeof(List<>);
var closedListType = openListType.MakeGenericType(stStructType);
var listOfStruct = Activator.CreateInstance(closedListType);
var result = processItemsMethod.Invoke(businessTypeInstance, new [] { listOfStruct });


Just for broaden the mind and even that i do not recommend this, you could get the List<stStruct> type from the parameter itself:

var closedListType = processItemsMethod.GetParameters()[0].ParameterType;

how to create a list of type obtained from reflection

var listType = typeof(List<>).MakeGenericType(myType)
var list = Activator.CreateInstance(listType);

var addMethod = listType.GetMethod("Add");
addMethod.Invoke(list, new object[] { x });

You might be able to cast to IList and call Add directly instead of looking up the method with reflection:

var list = (IList)Activator.CreateInstance(listType);
list.Add(x);

Generic list by using reflection

Closest you can get:

Type listType = typeof(List<>).MakeGenericType(_type);
IList list = (IList) Activator.CreateInstance(listType);

Instantiate generic c# List when the reflected type itself is a List

Have a look at this example, it uses the Type.GetGenericArguments Method to retrieve the lists inner type. Then proceed with reflection as usual.

    static void Main(string[] args)
{
Type modelType = GetMyType();
var myList = Activator.CreateInstance(modelType);

var listInnerType = modelType.GetGenericArguments()[0];
var listInnerTypeObject = Activator.CreateInstance(listInnerType);

var addMethod = modelType.GetMethod("Add");
addMethod.Invoke(myList, new[] { listInnerTypeObject });
}
static Type GetMyType()
{
return typeof(List<>).MakeGenericType((new Random().Next(2) == 0) ? typeof(A) : typeof(B));
}

class A { }
class B { }

Add instance of Generic List to object using reflection

Im running the code from your question with some minor changes to make it compile and it seems to work fine:

void Main()
{
Parse<Foo>();
}

public static T Parse<T>() where T : new()
{
var returnObj = new T();
PropertyInfo[] properties = typeof(T).GetProperties();
foreach (PropertyInfo p in properties)
{
// Get a meaningful property name
string ins = p.PropertyType.Name;
switch(ins)
{
// populate int
case "Int32":
p.SetValue(returnObj, 1 , null);
break;

// populate list
case "IList`1":
var list = new List<string>();
// This will throw the exception 'Parameter count mismatch.'
p.SetValue(returnObj, list, null);
break;
}
}
return returnObj;
}

public class Foo
{
public virtual int someInt {get; set;}
public virtual IList<string> list {get; set;}
}

If you change the Foo to have an indexer property that returns IList on the other hand you get the exception in your question:

public class Foo
{
public virtual int someInt {get; set;}
public virtual IList<string> this[int key]
{
get{ return null; }
set
{
}
}
}

Generates:

TargetParameterCountException: Parameter count mismatch.

instantiate a generic class using reflection

Regarding your update, you can pass any Type to MakeGenericType. For example, the following also works:

var myObject = new MyClass();

var myGenericObject = Activator.CreateInstance(typeof(GenericClass<>).MakeGenericType(typeof(MyClass)), myObject);

Console.WriteLine(myGenericObject.GetType());

Outputs:

ConsoleApplication1.GenericClass`1[ConsoleApplication1.MyClass]

myObject.GetType() also does the same thing:

var myGenericObject = Activator.CreateInstance(typeof(GenericClass<>).MakeGenericType(myObject.GetType()), myObject);


Related Topics



Leave a reply



Submit