Reputation: 7619
I am generating a List<T> with a runtime-determined type parameter. I'd like to invoke the ForEach method to iterate over the items in the list:
//Get the type of the list elements
Type elementType = GetListElementType(finfo);
Type listType = Type.GetType("System.Collections.Generic.List`1["
+ elementType.FullName + "], mscorlib", true);
//Get the list
var list = getList.Invoke(null, new Object[] { finfo.GetValue(myObject) });
MethodInfo listForEach = listType.GetMethod("ForEach");
//How do I do this? Specifically, what takes the place of 'x'?
listForEach.Invoke(list, new object[] { delegate ( x element )
{
//operate on x using reflection
}
});
Given a MethodInfo corresponding to the ForEach method contained in my runtime-generated list type, what's the proper way to invoke it using an anonymous method? The above is my first stab, but don't know how to declare the type of the anonymous method's parameter.
Upvotes: 3
Views: 3246
Reputation: 6682
Using generics is cool because it saves you a lot of coding and there's a theoretical gain in performance because it avoids boxing and unboxing, and so on, but I don't see the need to use dynamically created generics, using reflection and very slow methods.
Why don't you use a a simple IList interface and a foreach loop?
Upvotes: 0
Reputation: 27150
I couldn't make that an anonymous method works, but, if you have a defined method to execute when ForEach is called and it's overloaded to the possible data types it would work
class Program
{
static void Main(string[] args)
{
var sampleElement = "Foo";
Type listType = typeof(List<>).MakeGenericType(sampleElement.GetType());
Type actionType = typeof(Action<>).MakeGenericType(sampleElement.GetType());
var list = Activator.CreateInstance(listType);
var action = Delegate.CreateDelegate(actionType, null, typeof(Program).GetMethod ("ForEach"));
(list as List<string>).AddRange (new []{ "1", "2" });
listType.GetMethod ("ForEach").Invoke (list, new object []{ action });
}
public static void ForEach(string item)
{
Console.WriteLine(item);
}
}
Upvotes: 0
Reputation: 28332
You can do this:
var someGenericListYouCreated = ...;
var enumerable = someGenericListYouCreated as IEnumerable;
foreach(var foo in enumerable){
...
}
However, I'm working on way to do what you ACTUALLY want.
Edit:
Right, I hope this makes sense
private class Adapter<T>
{
private readonly Action<object> act;
public Adapter(Action<object> act){
this.act = act;
}
public void Do(T o)
{
act(o);
}
}
public static void Main(string[] args)
{
Type elementType = typeof(string);
var genericType = typeof(List<>).MakeGenericType(elementType);
var list = Activator.CreateInstance(genericType);
var addMethod = list.GetType().GetMethod("Add");
addMethod.Invoke(list, new object[] { "foo" });
addMethod.Invoke(list, new object[] { "bar" });
addMethod.Invoke(list, new object[] { "what" });
Action<object> printDelegate = o => Console.WriteLine(o);
var adapter = Activator.CreateInstance(typeof(Adapter<>).MakeGenericType(elementType), printDelegate);
var adapterDo = adapter.GetType().GetMethod("Do");
var adapterDelegate = Delegate.CreateDelegate(typeof(Action<string>), adapter, adapterDo);
var foreachMethod = list.GetType().GetMethod("ForEach");
foreachMethod.Invoke(list, new object[] { adapterDelegate });
}
What this does:
Note, you don't necessarily have to use Action if you know the type you're going to be processing. You could very easily use an Action and it'll work...
Upvotes: 5
Reputation: 121444
There are a number of issues here.
First, getting the type object of the type with the generic parameter by constructing the name of the type with string concatenation is a bit dodgy. You should do this instead:
Type genericType = typeof(List<>).MakeGenericType(new Type[] { listType });
This is a lot cleaner. Now, to invoke the ForEach method of an instance of this type, you will need an Action<T>
object. It's not entirely obvious for me if you want to use a lambda expression or a function pointer, but the point is that you pass the instance of Action<T>
just like a normal parameter:
methodInfo.Invoke(list, new object[] { x });
If you could clarify the origin of x (that is, the Action<T>
parameter) maybe we could give more help.
Upvotes: 0