2013-08-30 60 views
0

我不知道該主題的標題是否正確,但這是我想要的。c#遞歸分解類

比方說,我有一個類,它可以有另一個類,等等。

我想要什麼,它是獲取類的字段,最終在一個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); 
       } 
      }             
     } 

,但只得到了第一級。第一個參數是我想要分解的對象,第二個參數是返回類的列表對象。 你能幫助我嗎? 謝謝。

+0

那麼,爲什麼不串被分解成一個長度屬性的對象?什麼使它特別?還有哪些其他類型是「特殊」的,不應該再分解了? – Servy

+0

您是否嘗試過使用調試器並在行上設置斷點if(pi.GetType()。GetFields()。Length> 0)'?然後看看'pi.GetType()。GetFields()'的值是在'pi'指向地址時的值。 – FrankPl

+0

但我需要根據每個對象在多個層次上的列表。我希望我明白這一點。 – user2536272

回答

0

我覺得現在的問題是,fi.GetType()不返回類型「地址」,而是返回一個字段信息...

您可能希望測試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); 
     } 
    }             
} 
+0

謝謝,我會馬上測試。 – user2536272

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

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