c#递归分解类

时间:2013-08-30 15:56:08

标签: c# recursion

我不知道主题的标题是否正确,但这就是我想要的。

假设我有一个班级,而这个班级可以有另一个班级,依此类推。

我想要的是,获取类的字段,最终在List泛型中,具有多个级别。

例如,假设我有这个:

class address
{
public string street;
public string number;
}

class Student
{
public string name;
public string surname;
public address addr;
}

例如,我需要一个方法

Student s;
getItems(s);

将返回一个列表,其中包含:姓名,姓氏和另一个包含街道和号码的列表。

我试过了:

public void getItems(Object o, List<object> list)
        {
            FieldInfo[] f = new FieldInfo[o.GetType().GetFields().Length];

           f = o.GetType().GetFields();                            

            foreach (FieldInfo fi in f)
            {                    
                if (fi.GetType().GetFields().Length > 0)
                {
                    List<object> newList = new List<object>();
                    list.Add(newList);

                    getItems(fi, newList);
                }
                else
                {
                    list.Add(fi.Name);
                }
            }                                                
        }

但它只到达第一级。第一个参数是我想要分解的对象,第二个参数是返回类的列表对象。 你能帮帮我们吗? 感谢。

3 个答案:

答案 0 :(得分:1)

这种东西非常适合编写测试以找出方法!

简而言之,您想要的方法非常类似:

        List<string> GetFieldNames(IEnumerable<FieldInfo> fields)
        {
            var results = new List<string>();

            foreach (var fieldInfo in fields)
            {
                if (fieldInfo.FieldType.GetFields().Count() > 1)
                {
                    results.AddRange(GetFieldNames(fieldInfo.FieldType.GetFields()));
                }
                else
                {
                    results.Add(fieldInfo.Name);
                }
            }
            return results;
        }

演示该功能的完整测试类(以及我的解决方法)是:

using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using NUnit.Framework;

namespace stackoverflow_tests
{
    [TestFixture]
    public class ReflectionTest
    {
        class Address
        {
            public string Street;
            public string Number;
        }

        class Student
        {
            public string Name;
            public string Surname;
            public Address Address;
        }

        [Test]
        public void ShouldDisplayNestedClassFields()
        {
            var student = new Student();
            var studentFields = student.GetType().GetFields();

            Assert.IsNotNull(studentFields);
            Assert.AreEqual(3, studentFields.Count());

            var expectedNames = new []{"Name", "Surname", "Address"};
            var expectedTypes = new[] {typeof(string), typeof(string), typeof(Address)};

            for (var fieldIndex = 0; fieldIndex < 3; fieldIndex++)
            {
                var field = studentFields[fieldIndex];
                var fieldName = field.Name;
                Assert.AreEqual(expectedNames[fieldIndex], fieldName);

                var fieldType = field.FieldType;
                Assert.AreEqual(expectedTypes[fieldIndex], fieldType);

                var childFields = field.FieldType.GetFields();
                var childFieldCount = childFields.Count();
                var expectedFieldCount = fieldIndex == 2 ? 2 : 1;
                Assert.AreEqual(expectedFieldCount, childFieldCount);
            }
        }

        [Test]
        public void CanGetFieldNames()
        {
            var expectedResults = new List<string> {"Name", "Surname", "Street", "Number"};
            var student = new Student();
            var actual = GetFieldNames(student.GetType().GetFields());
            Assert.AreEqual(expectedResults, actual);
        }

        List<string> GetFieldNames(IEnumerable<FieldInfo> fields)
        {
            var results = new List<string>();

            foreach (var fieldInfo in fields)
            {
                if (fieldInfo.FieldType.GetFields().Count() > 1)
                {
                    results.AddRange(GetFieldNames(fieldInfo.FieldType.GetFields()));
                }
                else
                {
                    results.Add(fieldInfo.Name);
                }
            }
            return results;
        }

    }
}

答案 1 :(得分:0)

我认为问题是fi.GetType()不返回类型“address”但返回FieldInfo ...

您可能想要测试fi.FieldType ...

public static void getItems(Object o, List<object> list)
{
    FieldInfo[] f = new FieldInfo[o.GetType().GetFields().Length];

   f = o.GetType().GetFields();                            

    foreach (FieldInfo fi in f)
    {                    
        if (fi.FieldType.GetFields().Length > 0)
        {
            List<object> newList = new List<object>();
            list.Add(newList);

            getItems(fi, newList);
        }
        else
        {
            list.Add(fi.Name);
        }
    }                                                
}

答案 2 :(得分:0)

我终于成功完成了这项工作。 对于想要实际代码的人来说,这里是:

    public void getItems(Type t, List<object> list)
    {
       foreach(FieldInfo fi in t.GetFields(BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic))
       {
           list.Add(fi.Name);

           if(!fi.FieldType.Namespace.Equals("System"))
           {
               List<object> newList = new List<object>();
               list.Add(newList);
               getItems(fi.FieldType, newList);
           }
       }
    }