2009-07-13 10 views
3

.NET & C#では、ClassBにフィールドがClassAであるとします。 方法GetFieldsを簡単に使用してClassBのフィールドを一覧表示できます。 しかし、私はにものフィールドをリストしています。ClassBフィールドはです。にはフィールドがあります。 たとえば、ClassBのフィールドxは、フィールドb,s、およびiを持っています。私は(プログラムで)これらのフィールドをリストしたいと思う(以下のコードで私のコメントが示唆したように)。.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(); 

あなたはClassAClassZを持っている場合には再帰を使用して、あなたのコードに基づく完全なサンプルです。周期的なオブジェクトグラフがあれば、それは壊れます。

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:また、循環オブジェクトグラフのスタックオーバーフローを防ぐためのメカニズムが必要です。 indentパラメータに制限を設けることをお勧めします。

0

はここで素朴な実装です:注意すべき

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

     } 
    } 

いくつかの点:

  • は、スタックオーバーフローを防止します。つまり、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)); 
    } 
} 
関連する問題