如何使用反射调用List<T>的扩展方法“ElementAt”?

7

我有一个问题,就是在创建类型为List<MyClass01>的对象“oListType01”后,将其分配给另一个类型为“object”的对象“oObjectType”后,我不能再访问任何函数“ElementAt(1)”了。我尝试使用反射,但总是在“Invoke”方法中得到异常(参数冲突)。有人知道为什么吗? 米兰

MyClass01 oMy1 = new MyClass01();
oMy1._ID = "1";

MyClass01 oMy2 = new MyClass01();
oMy2._ID = "3";

IList<MyClass01> oListType01 = new List<MyClass01>();

oListType01.Add(oMy1);
oListType01.Add(oMy2);

object oObjectType = new object();

oObjectType = oListType01;

从这里开始,只有一个名为oObjectType的对象可用(向上发生在实际情况下的单独函数调用中)。在VS中,oObjectType显示了两个元素,我想通过反射访问它们。

MethodInfo mInfo = typeof(System.Linq.Enumerable).GetMethod("ElementAt").MakeGenericMethod(typeof(object));
object oSingleObject = mInfo.Invoke(oObjectType, new object[] { 1 });

你为什么要首先将它分配给一个对象?如果由于某种原因你必须这样做,并且如果你在编译时知道列表始终包含MyClass01实例的类型,为什么不直接将其强制转换回List<MyClass01>,像这样:((List<MyClass01>)oObjectType).ElementAt(1); - tclem
请看我的“回答”部分,我解释了在invoke中只能使用对oObjectType的引用(不能使用oListType01和MyClass01)。 - milan
4个回答

9
我假设你有充分的理由来执行这项操作,但这似乎有些不对。话虽如此,以下是一些代码可实现你所尝试的功能。
MethodInfo mInfo = typeof(System.Linq.Enumerable).GetMethod("ElementAt").MakeGenericMethod(typeof(MyClass01));
object oSingleObject = mInfo.Invoke(oObjectType, new object[] { oObjectType, 1 });

当我运行这段代码时,我会获得列表中的第二个元素。

请看一下我的“回答”,我解释了在invoke中只能使用oObjectType的引用(而不是oListType01)。 - milan
我修改了代码,使其在引用上调用。应该可以了。 - Shaun Bowe
这对我有用,谢谢!只有一个注意点:mInfo.Invoke()的第一个参数可以为null。我们正在调用静态方法,而不是实例方法的方法。 - Ryan Kirkman

0
如果我们可以安全地假设:
  • oObjectType是IEnumerable的一些T
那么这就是从中提取项的代码。
请注意,我真的很想知道这是否是正确的方法,但您没有给我们足够的信息来帮助您找出更好的方法,所以我们只能回答您提出的问题。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Diagnostics;

namespace ConsoleApplication2
{
    class MyClass01
    {
        public String _ID;

        public override string ToString()
        {
            return _ID;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            MyClass01 oMy1 = new MyClass01();
            oMy1._ID = "1";

            MyClass01 oMy2 = new MyClass01();
            oMy2._ID = "3";

            IList<MyClass01> oListType01 = new List<MyClass01>();

            oListType01.Add(oMy1);
            oListType01.Add(oMy2);

            object oObjectType = new object();

            oObjectType = oListType01;

            Test(oObjectType);

            Console.In.ReadLine();
        }

        private static void Test(object oObjectType)
        {
            Type tObject = oObjectType.GetType();
            Debug.Assert(tObject.IsGenericType);
            Debug.Assert(tObject.GetGenericArguments().Length == 1);
            Type t = tObject.GetGenericArguments()[0];

            Type tIEnumerable = typeof(IEnumerable<>).MakeGenericType(t);
            Debug.Assert(tIEnumerable.IsAssignableFrom(tObject));

            MethodInfo mElementAt =
                typeof(Enumerable)
                .GetMethod("ElementAt")
                .MakeGenericMethod(t);

            Console.Out.WriteLine("o[0] = " +
                mElementAt.Invoke(null, new Object[] { oObjectType, 0 }));
            Console.Out.WriteLine("o[1] = " +
                mElementAt.Invoke(null, new Object[] { oObjectType, 1 }));
        }
    }
}

0

ElementAt扩展方法可能在IEnumerable<T>上,因此当您将列表视为对象时,除非进行强制转换,否则扩展方法将不可用。可以使用((List<MyClass01>)oObjectType).ElementAt()或(oObjectType as List<MyClass01>).ElementAt()。

但我必须问一下,恕我直言,您为什么要这样做呢?我认为这里存在一些问题,可以使用接口更加简洁地解决。


IEnumerable扩展方法位于System.Linq.Enumerable类中。 - Steve Guidi
从 System.Linq.Enumerable . . . public static TSource ElementAt<TSource>(this IEnumerable<TSource> source, int index) { ... } - D. Patrick
请看上面我解释了限制条件的答案。 - milan

0

这与你的其他问题非常相似,但在这种情况下,静态的ElementAt方法实际上需要两个参数。请尝试以下代码:

object oSingleObject = mInfo.Invoke(null, new object[] { oObjectType, 1 });


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接