代码之家  ›  专栏  ›  技术社区  ›  Odrade

C:在运行时生成的列表上调用foreach<t>

  •  3
  • Odrade  · 技术社区  · 17 年前

    我正在生成一个带有运行时确定的类型参数的列表。我想调用foreach方法来迭代列表中的项目:

    //Get the type of the list elements
    Type elementType = GetListElementType(finfo);
    
    Type listType = Type.GetType("System.Collections.Generic.List`1[" 
                                  + elementType.FullName + "], mscorlib", true);
    
    //Get the list
    var list = getList.Invoke(null, new Object[] { finfo.GetValue(myObject) });
    
    MethodInfo listForEach = listType.GetMethod("ForEach");
    
    //How do I do this?  Specifically, what takes the place of 'x'?
    listForEach.Invoke(list, new object[] { delegate ( x element )
                                {
                                    //operate on x using reflection
                                }
                            });
    

    给定一个与运行时生成的列表类型中包含的foreach方法相对应的methodinfo,使用匿名方法调用它的正确方法是什么?上面是我的第一步,但不知道如何声明匿名方法参数的类型。

    4 回复  |  直到 17 年前
        1
  •  4
  •   jonnii    17 年前

    您可以这样做:

    var someGenericListYouCreated = ...;
    var enumerable = someGenericListYouCreated as IEnumerable;
    
    foreach(var foo in enumerable){
        ...
    }
    

    然而,我正在努力做你真正想要的。

    编辑:

    好吧,我希望这有道理

    private class Adapter<T>
    {
        private readonly Action<object> act;
    
        public Adapter(Action<object> act){
            this.act = act;
        }
    
        public void Do(T o)
        {
            act(o);
        }
    }
    
    public static void Main(string[] args)
    {
        Type elementType = typeof(string);
    
        var genericType = typeof(List<>).MakeGenericType(elementType);
        var list = Activator.CreateInstance(genericType);
    
        var addMethod = list.GetType().GetMethod("Add");
        addMethod.Invoke(list, new object[] { "foo" });
        addMethod.Invoke(list, new object[] { "bar" });
        addMethod.Invoke(list, new object[] { "what" });
    
        Action<object> printDelegate = o => Console.WriteLine(o);
    
        var adapter = Activator.CreateInstance(typeof(Adapter<>).MakeGenericType(elementType), printDelegate);
        var adapterDo = adapter.GetType().GetMethod("Do");
    
        var adapterDelegate = Delegate.CreateDelegate(typeof(Action<string>), adapter, adapterDo);
    
        var foreachMethod = list.GetType().GetMethod("ForEach");
    
        foreachMethod.Invoke(list, new object[] { adapterDelegate });
    }
    

    这是怎么做的:

    1. 创建通用列表(请注意,它使用的是typeof(list<gt;)
    2. 在此列表中添加一些字符串
    3. 创建新的委托,在本例中是一个操作
    4. 创建适配器类的实例
    5. 在适配器类上创建我们需要的类型的委托(操作)
    6. 呼叫前哨

    注意,如果您知道要处理的类型,就不必使用action。你可以很容易地使用一个动作,它会起作用…

        2
  •  0
  •   Tamas Czinege    17 年前

    这里有很多问题。

    首先,通过用字符串连接构造类型的名称来获得带有泛型参数的类型的类型对象有点不可靠。您应该这样做:

    Type genericType = typeof(List<>).MakeGenericType(new Type[] { listType });
    

    这要干净得多。现在,要调用此类型实例的foreach方法,需要 Action<T> 对象。对于我来说,如果您想使用lambda表达式或函数指针,这并不完全是显而易见的,但关键是要传递 行动与科技; 就像正常参数一样:

    methodInfo.Invoke(list, new object[] { x });
    

    如果你能澄清x的来源(即 行动与科技; 参数)也许我们可以提供更多帮助。

        3
  •  0
  •   albertein    17 年前

    我不能让匿名方法工作,但是,如果在调用foreach时有一个要执行的定义方法,并且它被重载到可能的数据类型,那么它将工作。

    class Program
    {
        static void Main(string[] args)
        {
            var sampleElement = "Foo";
    
            Type listType = typeof(List<>).MakeGenericType(sampleElement.GetType());
            Type actionType = typeof(Action<>).MakeGenericType(sampleElement.GetType());
    
            var list = Activator.CreateInstance(listType);
            var action = Delegate.CreateDelegate(actionType, null, typeof(Program).GetMethod ("ForEach"));
    
            (list as List<string>).AddRange (new []{ "1", "2" });
    
            listType.GetMethod ("ForEach").Invoke (list, new object []{ action });
        }
    
        public static void ForEach(string item)
        {
            Console.WriteLine(item);
        }
    }
    
        4
  •  0
  •   jmservera    17 年前

    使用泛型很酷,因为它可以节省大量的编码,并且在理论上可以提高性能,因为它可以避免装箱和拆箱等操作,但是我不认为需要使用动态创建的泛型,使用反射和非常慢的方法。

    为什么不使用一个简单的ilist接口和foreach循环?