在 C# 中使用反射进行投射
我创建了一个如下的通用函数(仅作为证明),它将采用 List
集合并反转它,返回一个新的 List
作为其集合输出。
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 });
这里有两个问题:
- 在第二行中,我希望提供类似于 myList 的 somthign,而不是提供
typeof(int)
.GetType().GetGenericArguments()[0].GetType() 以使事情更加灵活,因为我直到运行时才知道T
。执行此操作会导致调用运行时出现运行时错误,如下所示:“类型为‘System.Collections.Generic.List’1[System.Int32]’的对象无法转换为类型‘System.Collections.Generic.List’1[ System.RuntimeType]'。” Invoke()
方法的结果返回一个对象。调试时,我可以看到该对象是 List 类型,但尝试使用它告诉我,我的强制转换无效。我假设我需要使用反射将结果装箱为正确的类型(即在本例中,相当于(result as List
)。
是否有人有任何可以提供帮助的指针我可以解决这个问题吗?如果不清楚,我很抱歉,如果有人问我,我可以提供更多详细信息
。
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:
- In the second line, rather than supplying
typeof(int)
, I would like suppliy somthign akin tomyList.GetType().GetGenericArguments()[0].GetType()
in order to make things more flexible because I do not knowT
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]'." - 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<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
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您的
GetType()
太多了。每个人都会发生。myList.GetType().GetGenericArguments()[0]
是一个System.Type
——您正在寻找的那个。myList.GetType().GetGenericArguments()[0].GetType()
是一个描述System.Type
的System.Type
(嗯,实际上具体子类System.RuntimeType
)。另外,你的
ReverseList
函数是严重的矫枉过正。它执行额外的复制只是为了避免调用List.Reverse
。有一个更好的方法来规避这个问题:或
或
You've got one
GetType()
too many. Happens to everyone.myList.GetType().GetGenericArguments()[0]
IS aSystem.Type
-- the one you're looking for.myList.GetType().GetGenericArguments()[0].GetType()
is aSystem.Type
describingSystem.Type
(well, actually the concrete subclassSystem.RuntimeType
).Also, your
ReverseList
function is serious overkill. It does an extra copy just to avoid callingList.Reverse
. There's a better way to circumvent that:or
or
要将其作为
List
访问,是的,您需要使用反射找到 T(可能通过接口,例如typeof(IList<>)
,并使用更多反射和 MakeGenericMethod 等。老实说,这是不值得的:您最好检查非泛型IList
:不是好朋友。
泛型广告反射在 4.0 中 您还可以在此处使用
动态
和泛型来实现一些技巧。To access it as a
List<T>
, yes you'd need to find T using reflection (probably over the interfaces, for exampletypeof(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-genericIList
:Generics ad reflection are not good friends.
Note in 4.0 there are also some tricks you can do here with
dynamic
and generics.我能想到的唯一解决方法是传递一个空列表作为该方法的第二个参数并填充该列表 -
Invoke()
返回的引用将始终...
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:...