Reputation: 1869
I've created a generic function as below (just a s a proof) that will take a List<T>
collection and reverse it, returning a new List<T>
as its output.
public static List<T> ReverseList<T>(List<T> sourceList)
{
T[] outputArray = new T[sourceList.Count];
sourceList.CopyTo(outputArray);
return outputArray.Reverse().ToList();
}
The purpose of the proof is that I only know what T
is at runtime. I am therefore using reflection to call the above method as follows:
List<int> myList = new List<int>() { 1, 2, 3, 4, 5 }; // As an example, but could be any type for T
MethodInfo myMethod = this.GetType().GetMethod("ReverseList");
MethodInfo resultMethod = myMethod.MakeGenericMethod(new Type[] { typeof(int) });
object result = resultMethod.Invoke(null, new object[] { myList });
There are two problems here:
typeof(int)
, I would like suppliy somthign akin to myList.GetType().GetGenericArguments()[0].GetType()
in order to make things more flexible because I do not know T
until runtime. Doing this results in a runtime error when the Invoke runs as follows: "Object of type 'System.Collections.Generic.List'1[System.Int32]' cannot be converted to type 'System.Collections.Generic.List'1[System.RuntimeType]'."Invoke()
method returns an object. When debugging, I can see that the object is of type List, but attempting to use it tells me that I have an invalid cast. I assume that I need to use reflection to box the result in to the correct type (i.e. in this example, the equivalent of (result as List<int>
).Does anyone have any pointers that could help me resolve this? Apologies if this is not to clear, I can probably provide more detail if asked.
TIA
Upvotes: 4
Views: 3706
Reputation: 161012
The result of the Invoke() method returns an object. When debugging, I can see that the object is of type List, but attempting to use it tells me that I have an invalid cast. I assume that I need to use reflection to box the result in to the correct type (i.e. in this example, the equivalent of (result as List).
The only workaround for this is I can think of is to pass an empty list as the second parameter of the method and to populate that list - the reference returned by Invoke()
will always be only of type object, but inside the generic method you do have access to the type itself:
List<int> reverseList = new List<int>();
resultMethod.Invoke(null, new object[] { myList, reverseList });
...
public static void ReverseList<T>(List<T> sourceList, List<T> resultList)
{
T[] outputArray = new T[sourceList.Count];
sourceList.CopyTo(outputArray);
resultList.AddRange(outputArray.Reverse());
}
Upvotes: 1
Reputation: 283921
You've got one GetType()
too many. Happens to everyone.
myList.GetType().GetGenericArguments()[0]
IS a System.Type
-- the one you're looking for.
myList.GetType().GetGenericArguments()[0].GetType()
is a System.Type
describing System.Type
(well, actually the concrete subclass System.RuntimeType
).
Also, your ReverseList
function is serious overkill. It does an extra copy just to avoid calling List.Reverse
. There's a better way to circumvent that:
public static List<T> ReverseList<T>(List<T> sourceList)
{
return Enumerable.Reverse(sourceList).ToList();
}
or
public static List<T> ReverseList<T>(List<T> sourceList)
{
var result = new List<T>(sourceList);
result.Reverse();
return result;
}
or
public static List<T> ReverseList<T>(List<T> sourceList)
{
var result = new List<T>();
result.Capacity = sourceList.Count;
int i = sourceList.Count;
while (i > 0)
result.Add(sourceList[--i]);
return result;
}
Upvotes: 5
Reputation: 1064204
To access it as a List<T>
, yes you'd need to find T using reflection (probably over the interfaces, for example typeof(IList<>)
, and use more reflection and MakeGenericMethod etc. In all honesty, it isn't worth it: you would do better to check for the non-generic IList
:
var list = result as IList;
if (list != null)
{
// loop over list etc
}
Generics ad reflection are not good friends.
Note in 4.0 there are also some tricks you can do here with dynamic
and generics.
Upvotes: 3