在 C# 中使用反射进行投射

发布于 2024-10-19 14:29:33 字数 1316 浏览 1 评论 0原文

我创建了一个如下的通用函数(仅作为证明),它将采用 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 });

这里有两个问题:

  1. 在第二行中,我希望提供类似于 myList 的 somthign,而不是提供 typeof(int) .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)。

是否有人有任何可以提供帮助的指针我可以解决这个问题吗?如果不清楚,我很抱歉,如果有人问我,我可以提供更多详细信息

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:

  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. 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]'."
  2. 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

撩心不撩汉 2024-10-26 14:29:33

您的 GetType() 太多了。每个人都会发生。

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

myList.GetType().GetGenericArguments()[0].GetType() 是一个描述 System.TypeSystem.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;
}

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

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;
}
风筝在阴天搁浅。 2024-10-26 14:29:33

要将其作为 List 访问,是的,您需要使用反射找到 T(可能通过接口,例如 typeof(IList<>),并使用更多反射和 MakeGenericMethod 等。老实说,这是不值得的:您最好检查非泛型 IList

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

不是好朋友。

泛型广告反射在 4.0 中 您还可以在此处使用动态和泛型来实现一些技巧。

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.

萌辣 2024-10-26 14:29:33

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

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());
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文