简体   繁体   English

在C#中使用Reflection进行转换

[英]Cast using Reflection in C#

I've created a generic function as below (just asa proof) that will take a List<T> collection and reverse it, returning a new List<T> as its output. 我已经创建了一个通用函数(仅作为证明),它将采用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();
}

The purpose of the proof is that I only know what T is at runtime. 证明的目的是我只知道T在运行时是什么。 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: 这里有两个问题:

  1. In the second line, rather than supplying 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. 在第二行,而不是提供typeof(int) ,我想提供类似于myList.GetType().GetGenericArguments()[0].GetType()东西,以便使事情更灵活,因为我不知道T直到运行。 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运行时,执行此操作会导致运行时错误,如下所示:“System.Collections.Generic.List'1 [System.Int32]类型的对象'无法转换为类型'System.Collections.Generic.List'1 [ System.RuntimeType]”。”
  2. The result of the Invoke() method returns an object. Invoke()方法的结果返回一个对象。 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. 在调试时,我可以看到该对象是List类型,但是尝试使用它告诉我,我有一个无效的强制转换。 I assume that I need to use reflection to box the result in to the correct type (ie in this example, the equivalent of (result as List<int> ). 我假设我需要使用反射将结果打包成正确的类型(即在此示例中,等效于(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 TIA

You've got one GetType() too many. 你有一个GetType()太多了。 Happens to everyone. 发生在所有人身上。

myList.GetType().GetGenericArguments()[0] IS a System.Type -- the one you're looking for. myList.GetType().GetGenericArguments()[0]是一个System.Type - 你正在寻找的那个。

myList.GetType().GetGenericArguments()[0].GetType() is a System.Type describing System.Type (well, actually the concrete subclass System.RuntimeType ). myList.GetType().GetGenericArguments()[0].GetType()是一个System.Type描述System.Type (实际上具体子类System.RuntimeType )。


Also, your ReverseList function is serious overkill. 此外,您的ReverseList功能严重过度杀伤。 It does an extra copy just to avoid calling List.Reverse . 它只是为了避免调用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;
}

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 : 要以List<T>访问它,是的,您需要使用反射找到T(可能在接口上,例如typeof(IList<>) ,并使用更多反射和MakeGenericMethod等。说实话,它不是'值得的是:你会更好地检查非通用的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. 请注意,在4.0中,您还可以使用dynamic和泛型来完成一些技巧。

The result of the Invoke() method returns an object. Invoke()方法的结果返回一个对象。 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. 在调试时,我可以看到该对象是List类型,但是尝试使用它告诉我,我有一个无效的强制转换。 I assume that I need to use reflection to box the result in to the correct type (ie in this example, the equivalent of (result as List). 我假设我需要使用反射将结果打包成正确的类型(即在此示例中,等效于(结果为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: 唯一的解决方法是我能想到的是传递一个空列表作为方法的第二个参数并填充该列表 - Invoke()返回的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());
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM