2009-07-13 4 views
3

.NET & C#에서는 ClassB의 필드가 ClassA 인 것으로 가정합니다. 님의 필드를 목록으로 만들려면 GetFields 메서드를 쉽게 사용할 수 있습니다. 그러나 의 필드는 ClassB 필드에 표시되며 필드에는 필드가 있습니다. 예를 들어, ClassB의 필드 xb, si 필드를 포함합니다. 해당 필드를 (프로그래밍 방식으로) 나열하고 싶습니다 (아래 코드에서 내 의견에 의해 제안 된 것처럼)..NET, C#, Reflection : 필드 자체의 필드 필드를 나열하십시오.

class ClassA 
    { 
    public byte b ; 
    public short s ; 
    public int i ; 
    } 

class ClassB 
    { 
    public long l ; 
    public ClassA x ; 
    } 

class MainClass 
    { 
    public static void Main () 
     { 
     ClassA myAObject = new ClassA() ; 
     ClassB myBObject = new ClassB() ; 

     // My goal is this: 
     // ***Using myBObject only***, print its fields, and the fields 
     // of those fields that, *themselves*, have fields. 
     // The output should look like this: 
     // Int64 l 
     // ClassA x 
     //    Byte b 
     //    Int16 s 
     //    Int32 i 

     } 
    } 
+0

일부 불쾌한 LINQ 후보입니까? :) – xyz

답변

7

FieldInfo.FieldType을 사용하여 클래스의 필드 유형을 나타냅니다. 예 : 여기

fieldInfo.FieldType.GetFields(); 

ClassA 내부 ClassZ이 경우 재귀를 사용하여 코드를 기반으로 전체 샘플입니다. 순환 오브젝트 그래프가있는 경우 중단됩니다.

using System; 
using System.Reflection; 

class ClassA { 
    public byte b; 
    public short s; 
    public int i; 
} 

class ClassB { 
    public long l; 
    public ClassA x; 
} 

class MainClass { 

    public static void Main() { 
    ClassB myBObject = new ClassB(); 
    WriteFields(myBObject.GetType(), 0); 
    } 

    static void WriteFields(Type type, Int32 indent) { 
    foreach (FieldInfo fieldInfo in type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)) { 
     Console.WriteLine("{0}{1}\t{2}", new String('\t', indent), fieldInfo.FieldType.Name, fieldInfo.Name); 
     if (fieldInfo.FieldType.IsClass) 
     WriteFields(fieldInfo.FieldType, indent + 1); 
    } 
    } 

} 
+0

와우! 당신들은 매우 도움이되었습니다! 이것은 내가 일해야하는 첫 번째 제안이지만, 다른 제안도 매우 좋습니다! 모두에게 감사 드려요! – JaysonFix

+0

이것은 확실히 귀하의 경우에 적용됩니다. 미래에 좀 더 복잡한 객체로 계속 진행해야하거나 뭔가 올바르게 작동하지 않는다면 제 대답을 생각해보십시오. 그것은 C# 팀이 작성했으며, 코드는 사용자가 적합하다고 생각한대로 조정할 수 있지만 그대로 유연합니다. 그리고 당신은 환영합니다. 다행이 다 도움이됩니다! :-) 들여 쓰기의 멋진 사용을위한 –

+0

+1 : D –

5

이 클래스는 이미 존재합니다! Visual Studio 용 Microsoft C# 샘플을 살펴보십시오. http://code.msdn.microsoft.com/Release/ProjectReleases.aspx?ProjectName=csharpsamples&ReleaseId=8

특히, ObjectDumper 샘플이 n 레벨만큼 깊어 지므로보십시오. 예를 들어 :

ClassB myBObject = new ClassB(); 
... 
ObjectDumper.Write(myBObject, Int32.MaxValue); 
//Default 3rd argument value is Console.Out, but you can use 
//any TextWriter as the optional third argument 

이미 당신은 재귀 적 방법을 쓸 필요가 등, 그래프의 개체는 개체 유형에 대 열거 유형 대, 값 유형을 방문했는지 여부를 고려

0

을 촬영하고있다 객체를 취하고 해당 필드 (obj.GetType().GetFields())를 반복하며 원시 유형 필드의 값을 인쇄하고 클래스 (String 제외)를 호출합니다.

재귀와 함께 사용하기위한 들여 쓰기 크기에 대한 매개 변수가 필요합니다.

EDIT : 또한 순환 오브젝트 그래프의 스택 오버플로를 방지하는 메커니즘이 필요합니다. 들여 쓰기 매개 변수에 제한을 두는 것이 좋습니다.

private static void ListFields(Type type) 
    { 
     Console.WriteLine(type.Name); 
     foreach (var field in type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)) 
     { 
      Console.WriteLine(string.Format("{0} of type {1}", field.Name, field.FieldType.Name)); 
      if (field.FieldType.IsClass) 
      { 
       ListFields(field.FieldType); 
      } 

     } 
    } 

몇 가지 유의 :

0

여기 순진 구현의

  • 방지 스택 오버 플로우. 그것은 a -> b와 b -> a가 그러면 파열 될 것입니다.
  • 문자열은 참조 유형이지만 많은 사람들이 더 많은 값 유형과 같을 것으로 기대합니다. 따라서 유형이 문자열 인 경우 ListFields를 호출하지 않을 수도 있습니다.
1

다음을 시도해보십시오. 그것은 당신이 타입 계층 구조로 내려갈 때의 깊이를 제어 할 수 있고 비 프리미티브 타입으로 내려 가야만한다.

public static class FieldExtensions 
{ 
    public static IEnumerable<FieldInfo> GetFields(this Type type, int depth) 
    { 
    if(depth == 0) 
     return Enumerable.Empty<FieldInfo>(); 

    FieldInfo[] fields = type.GetFields(); 
    return fields.Union(fields.Where(fi => !fi.IsPrimitive) 
           .SelectMany(f => f.FieldType.GetFields(depth -1)); 
    } 
}