在C#中使用Reflection进行转换

时间:2011-02-28 15:38:23

标签: c# .net reflection

我创建了一个通用函数,如下所示(只是一个证明),它将采用List<T>集合并反转它,返回一个新的List<T>作为其输出。

public static List<T> ReverseList<T>(List<T> sourceList)
{
    T[] outputArray = new T[sourceList.Count];
    sourceList.CopyTo(outputArray);
    return outputArray.Reverse().ToList();
}

证明的目的是我只知道T在运行时是什么。因此,我使用反射来调用上述方法如下:

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

这里有两个问题:

  1. 在第二行中,我想提供typeof(int),而不是提供myList.GetType().GetGenericArguments()[0].GetType(),以便使事情变得更灵活,因为直到运行时我才知道T。这样做导致运行时错误时,调用运行如下:“类型的对象‘System.Collections.Generic.List'1 [System.Int32]’不能被转换为类型“System.Collections.Generic.List'1 [ System.RuntimeType]”。“
  2. Invoke()方法的结果返回一个对象。在调试时,我可以看到该对象是List类型,但是尝试使用它告诉我,我有一个无效的强制转换。我假设我需要使用反射将结果打包成正确的类型(即在此示例中,相当于(result as List<int>)。
  3. 有没有人有任何可以帮我解决这个问题的指针?如果不清楚,请道歉,如果被问到,我可以提供更多细节。

    TIA

3 个答案:

答案 0 :(得分:5)

你有一个GetType()太多了。发生在所有人身上。

myList.GetType().GetGenericArguments()[0]System.Type - 您正在寻找的那个。

myList.GetType().GetGenericArguments()[0].GetType()是描述System.Type的{​​{1}}(实际上是具体的子类System.Type)。


此外,您的System.RuntimeType功能严重过度。它只是为了避免调用ReverseList而执行额外的复制。有一种更好的方法来规避:

List.Reverse

public static List<T> ReverseList<T>(List<T> sourceList)
{
    return Enumerable.Reverse(sourceList).ToList();
}

public static List<T> ReverseList<T>(List<T> sourceList)
{
    var result = new List<T>(sourceList);
    result.Reverse();
    return result;
}

答案 1 :(得分:3)

要以List<T>的形式访问它,是的,您需要使用反射找到T(可能在界面上,例如typeof(IList<>),并使用更多反射和MakeGenericMethod等。老实说,这是不值得的:你会更好地检查非通用的IList

var list = result as IList;
if (list != null)
{
    // loop over list etc
}

泛型广告反映不是好朋友。

在4.0中注意,您可以使用dynamic和泛型来完成一些技巧。

答案 2 :(得分:1)

  

Invoke()方法的结果   返回一个对象。调试时,我   可以看到对象是类型的   列表,但尝试使用它告诉   我,我有一个无效的演员。一世   假设我需要使用反射   将结果打包到正确的位置   类型(即在这个例子中,   相当于(结果为List)。

唯一的解决方法是我能想到的是将空列表作为方法的第二个参数传递并填充该列表 - Invoke()返回的引用将始终只能是类型对象,但在泛型方法中你可以访问类型本身:

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