none
请教,反射时怎样可以遍历List的对象 RRS feed

  • 问题

  • 想写一个函数,把某个对象展现到一个TreeView控件。
    因为这个对象中有成员变量是List<A>类型,用到递归调用。

    写了个初稿如下,debug下面这段代码时,VS能够知道lstObj中A的类型和个数。
    既然VS能知道,应当是有办法能遍历A的对象并递归调用。

    尝试过,可以把A的类型取到一个String类型里,但不知怎样取到A的个数和对象。

            public static void Object2TreeNode(Object obj, TreeNodeCollection treeNode)
            {
                FieldInfo[] fields = obj.GetType().GetFields();

                TreeNode tn;

                foreach (FieldInfo field in fields)
                {
                    if (field.FieldType.IsGenericType)
                    {
                        tn = new TreeNode(field.Name);

                        Object lstObj = field.GetValue(obj);

                        Type typeLst = lstObj.GetType();

                        //foreach ()
                        //{
                        //Object2TreeNode()
                        //}
                    }
                    else
                    {
                        tn = new TreeNode(field.Name + "-" + field.GetValue(obj).ToString());
                    }
                    treeNode.Add(tn);
                }
            }

    请各位专家帮忙。
    2010年3月10日 12:40

答案

  • 你这里的object是一个实体,你只是想要知道这个实体的所有可见信息吧,如果知道类型的话就更简单了,直接一个强转就成强类型了,爱干嘛干嘛。如果不知道,那么就只有枚举所有变量、属性、函数(如 GetMethods ),然后用invoke方式来调用函数并获得返回值(函数调用比较危险,获取变量和属性还是可以的),还是一个蛮庞大的任务。

    看 Type 类的成员介绍,该有的就都有了
    霸王
    • 已标记为答案 ColinLeung 2010年3月12日 6:55
    2010年3月10日 14:02
  • 你好,

    参考下面代码试试。

      protected void Page_Load(object sender, EventArgs e)
        {
    
            if (!this.IsPostBack)
            {
                this.TreeView2.CheckedNodes.Clear();
            TreeNode tn = new TreeNode("RootNode");
            this.GenerateNode(ref tn);
            this.TreeView2.Nodes.Add(tn);
            }
            
    
        }
    
    public TreeNode GenerateNode(ref TreeNode tn)
        {
            Test t = new Test();
            t.Name = "TestName";
            List<SubTest> subTestList = new List<SubTest>();
            for (int i = 0; i < 2; i++)
            {
                SubTest st = new SubTest();
                st.SubName = "SubName" + i.ToString();
                List<int> intList = new List<int>();
                for (int k = 0; k < 2; k++)
                {
                    intList.Add(k);
                }
                st.IntList = intList;
                subTestList.Add(st);
            }
            t.ListObj = subTestList;
            ReflectFields(ref tn, t);
            return tn;
    
        }
        public void ReflectFields(ref TreeNode root, object o)
        {
            PropertyInfo[] fis = o.GetType().GetProperties();
            if (fis.Length != 0)
            {
    
    
                foreach (PropertyInfo item in fis)
                {
                    if (item.GetValue(o, null).GetType().IsGenericType)
                    {
                        TreeNode tn = new TreeNode(item.Name);
                        object obj = item.GetValue(o, null);
                        Type objType = obj.GetType();
                        int count = Convert.ToInt32(objType.GetProperty("Count").GetValue(obj, null));
                        for (int i = 0; i < count; i++)
                        {
                            object listItem = objType.GetProperty("Item").GetValue(obj, new object[] { i });
                            ReflectFields(ref tn, listItem);
                        }
                        root.ChildNodes.Add(tn);
    
                    }
                    else
                    {
                        TreeNode tn = new TreeNode(item.Name + "_" + item.GetValue(o, null).ToString());
                        root.ChildNodes.Add(tn);
                    }
                }
            }
            else
            {
                TreeNode tn = new TreeNode(o.GetType().ToString()+"_"+o.ToString());
                root.ChildNodes.Add(tn);
            }
        }
        public class Test
        {
            public string Name { get; set; }
            public List<SubTest> ListObj { get; set; }
        }
        public class SubTest
        {
            public string SubName { get; set; }
            public List<int> IntList { get; set; }
        }

    Microsoft Online Community Support
    2010年3月12日 3:44

全部回复

  • 你这里的object是一个实体,你只是想要知道这个实体的所有可见信息吧,如果知道类型的话就更简单了,直接一个强转就成强类型了,爱干嘛干嘛。如果不知道,那么就只有枚举所有变量、属性、函数(如 GetMethods ),然后用invoke方式来调用函数并获得返回值(函数调用比较危险,获取变量和属性还是可以的),还是一个蛮庞大的任务。

    看 Type 类的成员介绍,该有的就都有了
    霸王
    • 已标记为答案 ColinLeung 2010年3月12日 6:55
    2010年3月10日 14:02
  • 你好!
         实际上Type类型对泛型提供了很好的支持,你可以使用Type类型的GetGenericArguments()方法来获得泛型参数!
        
    周雪峰
    2010年3月10日 15:18
    版主
  • 你好,

    参考下面代码试试。

      protected void Page_Load(object sender, EventArgs e)
        {
    
            if (!this.IsPostBack)
            {
                this.TreeView2.CheckedNodes.Clear();
            TreeNode tn = new TreeNode("RootNode");
            this.GenerateNode(ref tn);
            this.TreeView2.Nodes.Add(tn);
            }
            
    
        }
    
    public TreeNode GenerateNode(ref TreeNode tn)
        {
            Test t = new Test();
            t.Name = "TestName";
            List<SubTest> subTestList = new List<SubTest>();
            for (int i = 0; i < 2; i++)
            {
                SubTest st = new SubTest();
                st.SubName = "SubName" + i.ToString();
                List<int> intList = new List<int>();
                for (int k = 0; k < 2; k++)
                {
                    intList.Add(k);
                }
                st.IntList = intList;
                subTestList.Add(st);
            }
            t.ListObj = subTestList;
            ReflectFields(ref tn, t);
            return tn;
    
        }
        public void ReflectFields(ref TreeNode root, object o)
        {
            PropertyInfo[] fis = o.GetType().GetProperties();
            if (fis.Length != 0)
            {
    
    
                foreach (PropertyInfo item in fis)
                {
                    if (item.GetValue(o, null).GetType().IsGenericType)
                    {
                        TreeNode tn = new TreeNode(item.Name);
                        object obj = item.GetValue(o, null);
                        Type objType = obj.GetType();
                        int count = Convert.ToInt32(objType.GetProperty("Count").GetValue(obj, null));
                        for (int i = 0; i < count; i++)
                        {
                            object listItem = objType.GetProperty("Item").GetValue(obj, new object[] { i });
                            ReflectFields(ref tn, listItem);
                        }
                        root.ChildNodes.Add(tn);
    
                    }
                    else
                    {
                        TreeNode tn = new TreeNode(item.Name + "_" + item.GetValue(o, null).ToString());
                        root.ChildNodes.Add(tn);
                    }
                }
            }
            else
            {
                TreeNode tn = new TreeNode(o.GetType().ToString()+"_"+o.ToString());
                root.ChildNodes.Add(tn);
            }
        }
        public class Test
        {
            public string Name { get; set; }
            public List<SubTest> ListObj { get; set; }
        }
        public class SubTest
        {
            public string SubName { get; set; }
            public List<int> IntList { get; set; }
        }

    Microsoft Online Community Support
    2010年3月12日 3:44
  • 对特定的Object是可以知道类型的,但这里Object的层级比较多,强转就不是一个函数递归调用能解决问题了。
    写函数invoke应该可以实现,所有被调用Object必须支持这个函数。

    感谢。
    2010年3月12日 6:58
  • 这个方式之前我试过了,typeLst.GetGenericArguments()可以取到List的类型,也可以把这个List的类型打出来。
    但有这个Type,还是不知道用什么方法可以遍历到具体的对象,因为我需要递归调用Object2TreeNode的时候传入。
    2010年3月12日 7:01
  • 就递归调用问题,你这里有一个类型是 List<A> 的成员变量(或者属性,这里假设是成员变量吧,一样),那么就这么干。

    Object2TreeNode(object obj)
    {
      Type t = obj.GetType();
      // 显示等操作,略
    
      // 获取所有成员,如果知道成员名,则可以不用这一步,直接到 InvokeMember 那里
      FieldInfo[] fields = t.GetFields();
      for(int i = 0; i < fields.Length; i++)
      {
        // 挨个找所有成员的类型,具体对应什么类型最好debug一下
        if(fields[i].FieldType == "List")
        {
          // 获取这个成员的内容
          List<object> list = t.InvokeMember("", BindingFlags.GetField, null, obj, null);
          foreach(object o in list)
          {
            // 这里就可以递归了
            Object2TreeNode(o);
          }
        }
      }
    }

    霸王
    2010年3月12日 9:24
  • KeFang Chen<abbr class="affil">MSFT</abbr><abbr class="affil">, 版主的也对,方式不同而已

                    if (item.GetValue(o, null).GetType().IsGenericType)
                    {
                        TreeNode tn = new TreeNode(item.Name);
                        object obj = item.GetValue(o, null); // 这里就获得了列表的实例 List<object>
                        Type objType = obj.GetType();
                        int count = Convert.ToInt32(objType.GetProperty("Count").GetValue(obj, null)); // =obj.Count
                        for (int i = 0; i < count; i++)
                        {
                            object listItem = objType.GetProperty("Item").GetValue(obj, new object[] { i }); // = obj.Item[i]
                            ReflectFields(ref tn, listItem); // 递归
                        }
                        root.ChildNodes.Add(tn);

                    }
    </abbr>

    霸王
    2010年3月12日 9:32