繁体   English   中英

C#递归分解类

[英]c# recursively decompose class

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

假设我有一个类,而该类又可以具有另一个类,依此类推。

我想要的是获取类的字段,最终在具有多个级别的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);
                }
            }                                                
        }

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

这种事情非常适合编写测试以找出前进的方向!

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

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

    }
}

我认为问题在于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);
        }
    }                                                
}

我终于设法做到了。 对于需要实际代码的人,这里是:

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM