.NET,C#,Reflection:列出字段的字段,字段本身具有字段

在.NET和C#中,假设ClassB有一个ClassA类型的字段。 可以使用方法GetFields轻松列出ClassB的字段。 但是,我还想列出那些本身有字段的ClassB字段的字段。 例如, ClassB的字段x具有字段bsi 。 我想(以编程方式)列出这些字段(正如我在以下代码中的评论所建议的那样)。

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

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

执行此操作的类已经存在! 看一下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 

它已经考虑了图表中的对象是否已被访问,值类型与对象类型与可枚举类型等。

请尝试以下方法。 它允许您控制下降到类型层次结构的深度,并且应该只下降到非基本类型。

 public static class FieldExtensions { public static IEnumerable GetFields( this Type type, int depth ) { if( depth == 0 ) return Enumerable.Empty(); FieldInfo[] fields = type.GetFields(); return fields.Union(fields.Where( fi => !fi.IsPrimitive ) .SelectMany( f => f.FieldType.GetFields( depth -1 ) ); } } 

您需要编写一个递归方法,该方法接受一个对象,遍历其字段( obj.GetType().GetFields() ),并打印基本类型字段的值,并为类( String除外)调用自身。

您需要一个用于递归的缩进大小参数。

编辑 :您还需要一些机制来防止循环对象图的堆栈溢出。 我建议对indent参数设置限制。

这是一个天真的实现:

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

有些事情需要注意:

  • 防止堆栈溢出。 那就是 – > b和b-> a然后这会爆炸。 您可以通过仅解析到某个级别来解决此问题
  • 字符串是引用类型,但很多人希望它更像是一个值类型。 因此,如果类型为字符串,您可能不想调用ListFields。